Xamarin Forms: Нажмите Событие Args Производный Тип - PullRequest
0 голосов
/ 17 ноября 2018

У меня есть такой код, который отлично работает:

type App() =
    inherit Application()

    let stack = StackLayout(VerticalOptions = LayoutOptions.Center)
    let label = Label(XAlign = TextAlignment.Center, Text = "Welcome to F# Xamarin.Forms!")

    do
        let tapRecognizer = new TapGestureRecognizer()
        let handleTapEvent (sender:Object) (args:EventArgs) =
            label.Text <- "Tapped at " + DateTime.Now.ToString() 
            ()

        let tapEventHandler = new EventHandler(handleTapEvent)
        tapRecognizer.Tapped.AddHandler(tapEventHandler)
        label.GestureRecognizers.Add(tapRecognizer)

Однако, когда я изменяю аргументы из EventArgs на производный тип, подобный этому:

type TapEventArgs(someId:int) = 
          inherit EventArgs()
          member this.SomeId = someId

        let handleTapEvent (sender:Object) (args:TapEventArgs) =
            label.Text <- args.SomeId.ToString() + " tapped"
            ()

Я получаю следующееошибка при вызове AddHandler

Тип 'EventArgs' не совместим с типом 'TapEventArgs'

Также, если я изменю EventHandler следующим образом:

let tapEventHandler = new EventHandler<TapEventArgs>(handleTapEvent)

Я получаю эту ошибку

 This expression was expected to have type 'EventHandler' 
but here has type    'EventHandler<TapEventArgs>'

Любой способ заставить этот производный тип?

Ответы [ 2 ]

0 голосов
/ 16 декабря 2018

Проблема здесь в том, что типы разные, и это то, что F # говорит вам.Тип tapRecognizer.Tapped имеет EventHandler, поэтому, когда он вызывается, он будет иметь тип EventHandler, т.е. не EventHandler<TapEventArgs>, который является другим типом.Изменить это невозможно, и подкласс TapGestureRecognizer также невозможен, так как класс запечатан.

Кроме того, код, который вы разместили, будет трудно скомпилировать, поскольку он содержит циклические ссылки, которые F # предотвращает.TapEventArgs требует label, что определено в App.App зависит от TapEventArgs.Было бы невозможно обновить пользовательский интерфейс с TapEventArgs, вместо этого необходимо было бы передать функцию или выставить состояние.

Существует решение, использующее шаблон Command, который позволяет некоторой информациипередаваться в обратный вызов и избегает циклических зависимостей.TapGestureRecognizer имеет свойство CommandParameter, где может быть установлено значение (типа obj).Обратный вызов может быть предоставлен через свойство Command, которое может получить это значение.Вот полный пример:

open Xamarin.Forms
open System

type App() as this =
    inherit Application()

    let stack = StackLayout(VerticalOptions = LayoutOptions.Center)
    let label = Label(XAlign = TextAlignment.Center, Text = "Welcome to F# Xamarin.Forms!")

    do
        let tapRecognizer = new TapGestureRecognizer()
        let handleTapEvent (x:obj) = 
            match x with 
            | :? int as someId -> label.Text <- someId.ToString() + " tapped"
            | _ -> label.Text <- "Tapped at " + DateTime.Now.ToString() 

        tapRecognizer.Command <- new Command(Action<obj>(fun x -> handleTapEvent x))
        label.GestureRecognizers.Add(tapRecognizer)
        stack.Children.Add label

        tapRecognizer.CommandParameter <- 42 // The value to be passed to the Command's callback
        this.MainPage <- ContentPage(Content = stack)

Обратите внимание, что приведение типов должно использоваться из-за способа определения типов в Xamarin.Forms (для свойства используется obj).

0 голосов
/ 17 ноября 2018

F # не вставляет downcasts автоматически, как это делает C # (и это хорошо, а не ошибка). Вы не можете передать тип-потомок там, где ожидается тип-предок.

Для того, чтобы позвонить AddHandler, вам нужно вручную вставить downcast, используя оператор downcast :>, например:

tapRecognizer.Tapped.AddHandler(tapEventHandler :> EventHandler<EventArgs>)

Когда целевой тип уже известен (как в вашем случае), вы можете использовать подчеркивание вместо него, чтобы позволить компилятору F # вывести его из контекста:

tapRecognizer.Tapped.AddHandler(tapEventHandler :> _)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...