Search code examples
c#xamarin.formstelerik

In a Telerik ListView in Xamarin Forms, how do I handle a right click event for an element on Windows?


My company has a cross-platform application primarily used on mobile devices using Xamarin with some controls by Telerik. Recently, we have been putting more work in to get it to work properly on all platforms (it was originally a port of an Android Java application). The sticking point at the moment is Windows: while almost everything works fairly well, a Telerik ListView is giving us trouble.

We currently use a long press event to show UI for deleting an item. This works perfectly. This is using a GestureRecognizer within a Telerik ListView. The problem is that we cannot find a way to get similar behavior with a mouse: clicking on the item has an effect that we wish to preserve, and it already contains an irreplaceable checkbox. Ideally, I'd set a right click event and be done with it, but there is no right click event available on the Telerik ListView control. Since the control is not a UIElement, I cannot locate its children in any of the ways I'm used to, and the nodes themselves seem to be replaced at runtime in the live visual tree.

I can see an ExtendedListViewItem control, which seems to be the one I'd like to give a mouse event handler, but I don't know any way to refer to those nodes from the top. It gets even trickier, because these pages are all within a .NET Standard 2.0 class library, so any platform-specific code (like say VisualTreeHelper) can only be added to the UWP application and then somehow abstracted back to this library of shared UI.

I know that this is a very specific question and may be difficult to answer, but searching for any of the parts of what I'm trying to do seems to get me a large amount of irrelevant guides and information.


Solution

  • I evaluated the approach to create 'RightClicked' event in the UWP part of the RadListView component and provide that notification to the XamarinForms part of the control. Technically this is possible but at the time of writing the UWP related class that should provide the notification is internal. This means that using the UWP ListViewItems to provide that notification is not possible.

    Since, most likely you have already set a custom ItemTemplate to the RadListView in XamarinForms, you can consider creating a custom XamrinForms control (e.g. Grid, Frame, Border, Label...) which has custom renderer for UWP. That renderer can subscribe to the UIElement.RightTapped Event and retransmit the notification to the XamarinForms part of the control.

    public class MyRightClickGridRenderer : ViewRenderer<MyRightClickGrid, Grid>
    {
        protected override void OnElementChanged(ElementChangedEventArgs<MyRightClickGrid> e)
        {
            if (this.Element != null)
            {
                if (this.Control == null)
                {
                    var uwpGrid = new Grid { IsRightTapEnabled = true, Background = new SolidColorBrush(Colors.Transparent) };
                    uwpGrid.RightTapped += UwpGrid_RightTapped;
                    this.SetNativeControl(uwpGrid);
                }
            }
            if (this.Element == null)
            {
                if (this.Control != null)
                {
                    ((Grid)this.Control).RightTapped -= UwpGrid_RightTapped;
                }
            }
        }
    
        private void UwpGrid_RightTapped(object sender, Windows.UI.Xaml.Input.RightTappedRoutedEventArgs e)
        {
            ((MyRightClickGrid)this.Element).RaiseRightClicked(sender);
        }
    }
    

    and in the XamarinForms project you could create something similar

    public class MyRightClickGrid : Grid
    {
        public event EventHandler<TappedEventArgs> RightTapped;
        public void RaiseRightClicked(object sender)
        {
            this.RightTapped?.Invoke(this, new TappedEventArgs(null));
        }
    }
    

    Once you create this control you can use it in XAML like this:

    <telerikListView:RadListView>
      <telerikListView:RadListView.ItemTemplate>
        <DataTemplate>
          <telerikListViewPrimitives:ListViewTemplateCell>
            <telerikListViewPrimitives:ListViewTemplateCell.View>
              <MyNamespace:MyRightClickGrid >
                ***
              </MyNamespace:MyRightClickGrid >
            </telerikListViewPrimitives:ListViewTemplateCell.View>
          </telerikListViewPrimitives:ListViewTemplateCell>
        </DataTemplate>
      </telerikListView:RadListView.ItemTemplate>
    </telerikListView:RadListView>
    

    Let me know if this works for you.

    P.S. One advantage to this approach is that you can use the same renderer to retrieve the position where the click originated. This feature is still not supported by XamarinForms and you should create similar logic for each platform to get that information.