Search code examples
c#xamlxamarineventhandler

How to fire off event handler in xaml from a different class than the code behind?


When tapping the JournalWarning label I want to raise an event for "reconnecting"

I have an event handler in one class that raises different events based on a switch case. In one of my views I want to fire off a "reconnecting" event when a label is tapped. I'm having a difficult time figuring out how to do this especially since the event is not in the code behind but a different class in general.

I'm not great with dealing with event handlers and data binding yet but hoping after I get this working better then I can wrap my head around it more.

In the code behind I have some data binding going on that is hitting my event handler but I haven't gotten to work work with TapGestureRecognizer one yet.

I thought it might be something like JournalWarning.SetBinding(TapGestureRecognizer, "Reconnecting");

This is in my JournalSocket.cs

private void Sock_DabSocketEvent(object sender, DabSocketEventHandler e)
        {
            //An event has been fired by the socket. Respond accordingly


            //Log the event to the debugger
            Debug.WriteLine($"{e.eventName} was fired with {e.data}");

            //Take action on the event
            switch (e.eventName.ToLower())
            {
                case "disconnected": //Socket disconnected
                    Sock_Disconnected(e.data);
                    break;
                case "connected": //Socket connected
                    Sock_Connected(e.data);
                    break;
                case "reconnecting": //Socket reconnecting
                    //do nothing for now
                    break;
                case "reconnected": //Socket reconnected
                    Sock_Connected(e.data);
                    break;
                case "room_error": //Error with a room
                    Sock_ErrorOccured(e.eventName, e.data);
                    break;
                case "join_error": //Error joining
                    Sock_ErrorOccured(e.eventName, e.data);
                    break;
                case "auth_error": //Error with authentication
                    Sock_ErrorOccured(e.eventName, e.data);
                    break;
                case "update": //update happened externally
                    Sock_ExternalUpdateOccured(e.eventName, e.data);
                    break;
                default:
                    break;
            }
        }

This is my PlayerPage.xaml

<Label x:Name="JournalWarning"
                           Text="Your device has lost its connection to the journal server. Journals cannot be viewed or edited at this time. Tap here to try and reconnect."
                           Style="{StaticResource warningLabelStyle}"
                           FontSize="Medium"
                           VerticalOptions="EndAndExpand"
                           AutomationProperties.IsInAccessibleTree="true">
                        <Label.GestureRecognizers>
                            <TapGestureRecognizer Tapped="OnReconnect"/>
                        </Label.GestureRecognizers>
                    </Label>

This is my code behind PlayerPage.cs where I have some other successful data binding going on and thinking I can accomplish what I want here as well. Might be totally wrong though.

 void BindControls(bool BindToEpisode, bool BindToPlayer)
        {
            if (BindToEpisode)
            {
                //Journal
                JournalTitle.BindingContext = Episode;
                JournalTitle.SetBinding(Label.TextProperty, "title");
                JournalContent.BindingContext = journal;
                JournalContent.SetBinding(Editor.TextProperty, "Content");
                JournalContent.SetBinding(Editor.IsEnabledProperty, "IsConnected");
                JournalWarning.BindingContext = journal;
                JournalWarning.SetBinding(IsVisibleProperty, "IsDisconnected");
            }

Any help is greatly appreciated!


Solution

  • If you want to bind Tap event to Model , you should use ICommand to realize it.

    Applications that use the Model-View-ViewModel (MVVM) pattern typically use ICommand rather than wiring up event handlers directly. The TapGestureRecognizer can easily support ICommand either by setting the binding in code:

    <Label x:Name="JournalWarning"
           Text="Your device has lost its connection to the journal server. Journals cannot be viewed or edited at this time. Tap here to try and reconnect."
           Style="{StaticResource warningLabelStyle}"
           FontSize="Medium"
           VerticalOptions="EndAndExpand"
           AutomationProperties.IsInAccessibleTree="true">
          <Label.GestureRecognizers>
               <TapGestureRecognizer Command="{Binding TapCommand}" CommandParameter="paramater"/>
          </Label.GestureRecognizers>
    </Label>
    

    The complete code for this view model can be found in the sample. The relevant Command implementation details are shown below:

    public class TapViewModel : INotifyPropertyChanged
    {
        int taps = 0;
        ICommand tapCommand;
        public TapViewModel () {
            // configure the TapCommand with a method
            tapCommand = new Command (OnTapped);
        }
        public ICommand TapCommand {
            get { return tapCommand; }
        }
        void OnTapped (object s)  {
            taps++;
            Debug.WriteLine ("parameter: " + s);
        }
        //region INotifyPropertyChanged code omitted
    }