UWP item list item context menu

I am searching on the Internet how to add a context menu for a ListView . So far I have found one that actually displays context

 <ListView> ... RightTapped="ContactsListView_RightTapped" > ... <ListView.Resources> <MenuFlyout x:Name="allContactsMenuFlyout"> <MenuFlyout.Items> <MenuFlyoutItem x:Name="Edit" Text="Edit"/> <MenuFlyoutItem x:Name="Remove" Text="Remove" Click="Remove_Click"/> </MenuFlyout.Items> </MenuFlyout> </ListView.Resources> ... </ListView> private void ContactsListView_RightTapped(object sender, RightTappedRoutedEventArgs e) { ListView listView = (ListView)sender; allContactsMenuFlyout.ShowAt(listView, e.GetPosition(listView)); } private void Remove_Click(object sender, RoutedEventArgs e) { } 

The problem is that I cannot get the item on which the context menu was displayed. Another problem is that the context menu is also displayed outside the list item (for example, at borders). And since the triggered event is RightTapped, I'm not sure if the context menu will be displayed when the mobile devices are pressed for a long time. I cannot verify this because my emulators are currently not working. Since this should be a universal windows application, I expected a very simple and effective way to create context menus for ListView items.

+6
source share
3 answers

The problem is that I cannot get the item on which the context menu was displayed.

For this problem, if you add data to the ListView as follows:

 <ListView RightTapped="ListView_RightTapped"> <x:String>First Item</x:String> <x:String>Second Item</x:String> <x:String>Third Item</x:String> <x:String>Fourth Item</x:String> <ListView.Resources> <MenuFlyout x:Name="allContactsMenuFlyout"> <MenuFlyout.Items> <MenuFlyoutItem x:Name="Edit" Text="Edit" /> <MenuFlyoutItem x:Name="Remove" Text="Remove" Click="Remove_Click" /> </MenuFlyout.Items> </MenuFlyout> </ListView.Resources> </ListView> 

You can get the context of the element in the RightTapped event as follows:

 private void ListView_RightTapped(object sender, RightTappedRoutedEventArgs e) { ListView listView = (ListView)sender; allContactsMenuFlyout.ShowAt(listView, e.GetPosition(listView)); var a = ((FrameworkElement)e.OriginalSource).DataContext; } 

In this case, "a" will directly receive the contents of the string format with the item pressed.

If you add your data to a ListView using a DataTemplate as follows:

 <ListView RightTapped="ListView_RightTapped" ItemsSource="{x:Bind list}"> <ListView.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding text}" /> </DataTemplate> </ListView.ItemTemplate> <ListView.Resources> <MenuFlyout x:Name="allContactsMenuFlyout"> <MenuFlyout.Items> <MenuFlyoutItem x:Name="Edit" Text="Edit" /> <MenuFlyoutItem x:Name="Remove" Text="Remove" Click="Remove_Click" /> </MenuFlyout.Items> </MenuFlyout> </ListView.Resources> </ListView> 

and usually when using a DataTemplate we add ObservableCollection data as follows:

 private ObservableCollection<List> list = new ObservableCollection<List>(); public MainPage() { this.InitializeComponent(); list.Clear(); list.Add(new List { text = "Item 1" }); list.Add(new List { text = "Item 2" }); list.Add(new List { text = "Item 3" }); list.Add(new List { text = "Item 4" }); list.Add(new List { text = "Item 5" }); } 

The "list" class is pretty simple for the test:

 public class List { public string text { get; set; } } 

Then we can also get the DataContext in the RightTapped event:

 private void ListView_RightTapped(object sender, RightTappedRoutedEventArgs e) { ListView listView = (ListView)sender; allContactsMenuFlyout.ShowAt(listView, e.GetPosition(listView)); var a = ((FrameworkElement)e.OriginalSource).DataContext; } 

But this time, โ€œaโ€ is actually a โ€œListโ€ object (see the โ€œListโ€ class) inside an element, because the contents of the element are now a โ€œListโ€ object, not a string. Therefore, we can get the text property of this object as follows way:

 private void ListView_RightTapped(object sender, RightTappedRoutedEventArgs e) { ListView listView = (ListView)sender; allContactsMenuFlyout.ShowAt(listView, e.GetPosition(listView)); var a = ((FrameworkElement)e.OriginalSource).DataContext as List; var content = a.text; } 

I think that in the end you will want to edit the content in the click Button Flyout , you can do this, for example, as follows:

 private string content; private void ListView_RightTapped(object sender, RightTappedRoutedEventArgs e) { ListView listView = (ListView)sender; allContactsMenuFlyout.ShowAt(listView, e.GetPosition(listView)); var a = ((FrameworkElement)e.OriginalSource).DataContext as List; content = a.text; } private void Remove_Click(object sender, RoutedEventArgs e) { foreach (var item in list.ToList()) { if (item.text == content) { list.Remove(item); } } content = ""; } 

Another problem is that the context menu is also displayed outside the list item (for example, at borders).

Can you explain this? I canโ€™t figure it out. Do you mean displaying content, for example, in Flyout ? If so, I think the method above can solve this problem. If not, you can leave a comment and I will see if this problem can be solved.

And since the triggered event is RightTapped, I'm not sure if the context menu will be displayed when the mobile devices are pressed for a long time.

I think the โ€œlong clickโ€ event here denotes a Holding event like this?

 private void ListView_Holding(object sender, HoldingRoutedEventArgs e) { ListView listView = (ListView)sender; allContactsMenuFlyout.ShowAt(listView, e.GetPosition(listView)); var a = ((FrameworkElement)e.OriginalSource).DataContext as List; content = a.text; } 

I just test it on Mobile Emulator, it works great. Although I wrote a rather long answer here, but the key point is quite simple, you can simply use ((FrameworkElement)e.OriginalSource).DataContext to get the context of the element.

+10
source

Use the command instead of the Click event. You can pass the clicked item to CommandParameter

  <MenuFlyout x:Name="allContactsMenuFlyout"> <MenuFlyout.Items> <MenuFlyoutItem x:Name="Edit" Text="Edit"/> <MenuFlyoutItem x:Name="Remove" Text="Remove" Command="{Binding Path=DataContext.DeleteItemTappedCommand , ElementName=ListViewName}" CommandParameter="{Binding }"/> </MenuFlyout.Items> </MenuFlyout> In viewModel.cs public DelegateCommand<object> DeleteItemTappedCommand { get; set; } public viewModel() { DeleteItemTappedCommand = new DelegateCommand<object>(DeleteItemClicked); } private void DeleteItemClicked(object obj) { //Your code. Here obj is clicked item } 
+3
source

Add popup to datatemplate. Use the command to handle events. See sample code here:

 <DataTemplate x:Name="ListItemTemplate" > <Grid x:Name="gridItem" RightTapped="gridItem_RightTapped"> <Grid.ColumnDefinitions> <ColumnDefinition Width="auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Image Name="imgProduct" Width="50" Height="50" Grid.Column="0" Source="{Binding ProductUrl}" Margin="0,5,10,5" VerticalAlignment="Center" ></Image> <TextBlock Name="tbName" Text="{Binding Name}" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Stretch" ></TextBlock> <FlyoutBase.AttachedFlyout> <MenuFlyout> <MenuFlyoutItem Text="Delete" Command="{Binding DataContext.DeleteCommand, ElementName=contentGrid}" CommandParameter="{Binding}" /> </MenuFlyout> </FlyoutBase.AttachedFlyout> </Grid> </DataTemplate> 

Code behind:

 private void gridItem_RightTapped(object sender, RightTappedRoutedEventArgs e) { FlyoutBase.ShowAttachedFlyout(sender as FrameworkElement); } 

You can get the full solution here: https://code.msdn.microsoft.com/How-to-implement-flyout-ef52517f

0
source

All Articles