UWP ListView 项目上下文菜单
UWP ListView Item context menu
我正在互联网上搜索如何为 ListView
添加上下文菜单。到目前为止,我已经找到了一个实际显示上下文的
<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) {
}
问题是我无法获取显示上下文菜单的项目。另一个问题是上下文菜单也显示在列表视图项目之外(例如在边框上)。由于触发的事件是 RightTapped,我不确定在移动设备上长按时是否会显示上下文菜单。我无法对其进行测试,因为我的模拟器目前无法正常工作。因为它应该是通用的 windows 应用程序,所以我期待有一些非常简单有效的方法来为 ListView 项目创建上下文菜单。
使用 Command
而不是 Click
事件。您可以在 CommandParameter
中传递点击的项目
<MenuFlyout x:Name="allContactsMenuFlyout">
<MenuFlyout.Items>
<MenuFlyoutItem x:Name="Edit" Text="Edit"/>
<MenuFlyoutItem x:Name="Remove" Text="Remove" Command="{Binding Path=DeleteItemTappedCommand}" CommandParameter="{Binding ElementName=ArchivedMessages_ListView, Path=SelectedItem}"/>
</MenuFlyout.Items>
</MenuFlyout>
在您的 ViewModel 中
public DelegateCommand<object> DeleteItemTappedCommand { get; set; }
public YourViewModel()
{
DeleteItemTappedCommand = new DelegateCommand<object>(DeleteItemClicked);
}
private void DeleteItemClicked(object obj)
{
// adjust object type to your templated source type
}
或 CommunityToolkit.MVVM
用户:
[ICommand]
private void DeleteItemClicked(object obj)
{
// adjust object type to your templated source type
}
The problem is I'm not able to get item on which the context menu was displayed.
对于这个问题,如果你像这样向ListView
添加数据:
<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>
您可以像这样在 RightTapped
事件中获取项目的上下文:
private void ListView_RightTapped(object sender, RightTappedRoutedEventArgs e)
{
ListView listView = (ListView)sender;
allContactsMenuFlyout.ShowAt(listView, e.GetPosition(listView));
var a = ((FrameworkElement)e.OriginalSource).DataContext;
}
这种场景下,"a"会直接获取点击item的字符串格式内容
如果您像这样使用 DataTemplate
将数据添加到 ListView
:
<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>
通常在使用DataTemplate
时,我们通过ObservableCollection
添加数据,像这样:
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" });
}
"List" class这里很简单,测试一下:
public class List
{
public string text { get; set; }
}
然后我们也可以在RightTapped
事件中得到DataContext
:
private void ListView_RightTapped(object sender, RightTappedRoutedEventArgs e)
{
ListView listView = (ListView)sender;
allContactsMenuFlyout.ShowAt(listView, e.GetPosition(listView));
var a = ((FrameworkElement)e.OriginalSource).DataContext;
}
但是这次"a"实际上是item里面的'List'对象(请参考"List"class),因为item的内容是现在是 'List' 对象,不再是字符串。所以我们可以这样得到这个对象的文本属性:
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;
}
我认为最终你想编辑 Flyout
的 Button click 事件中的内容,你可以这样做,例如:
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 issue is that the context menu is displayed also outside of list view item (e.g. on borders).
你能解释一下吗?我不是很明白。您的意思是在 Flyout
中显示内容?如果是这样,我认为上面的方法可以解决这个问题。如果不行,可以留言,我看看能不能解决这个问题。
And since the event that is triggered is RightTapped, I'm not sure if the context menu would be displayed on long click on mobile devices.
我觉得这里的"long click"事件是指这样的Holding
事件?
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;
}
我刚刚在移动模拟器上测试了它,它工作正常。虽然我在这里写了一个很长的答案,但是关键点很简单,你可以使用 ((FrameworkElement)e.OriginalSource).DataContext
来获取项目的上下文。
在数据模板中添加浮出控件。使用命令来处理事件。
请在此处查看示例代码:
<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>
后面的代码:
private void gridItem_RightTapped(object sender, RightTappedRoutedEventArgs e)
{
FlyoutBase.ShowAttachedFlyout(sender as FrameworkElement);
}
您可以在这里获得完整的解决方案:https://code.msdn.microsoft.com/How-to-implement-flyout-ef52517f
我正在互联网上搜索如何为 ListView
添加上下文菜单。到目前为止,我已经找到了一个实际显示上下文的
<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) {
}
问题是我无法获取显示上下文菜单的项目。另一个问题是上下文菜单也显示在列表视图项目之外(例如在边框上)。由于触发的事件是 RightTapped,我不确定在移动设备上长按时是否会显示上下文菜单。我无法对其进行测试,因为我的模拟器目前无法正常工作。因为它应该是通用的 windows 应用程序,所以我期待有一些非常简单有效的方法来为 ListView 项目创建上下文菜单。
使用 Command
而不是 Click
事件。您可以在 CommandParameter
<MenuFlyout x:Name="allContactsMenuFlyout">
<MenuFlyout.Items>
<MenuFlyoutItem x:Name="Edit" Text="Edit"/>
<MenuFlyoutItem x:Name="Remove" Text="Remove" Command="{Binding Path=DeleteItemTappedCommand}" CommandParameter="{Binding ElementName=ArchivedMessages_ListView, Path=SelectedItem}"/>
</MenuFlyout.Items>
</MenuFlyout>
在您的 ViewModel 中
public DelegateCommand<object> DeleteItemTappedCommand { get; set; }
public YourViewModel()
{
DeleteItemTappedCommand = new DelegateCommand<object>(DeleteItemClicked);
}
private void DeleteItemClicked(object obj)
{
// adjust object type to your templated source type
}
或 CommunityToolkit.MVVM
用户:
[ICommand]
private void DeleteItemClicked(object obj)
{
// adjust object type to your templated source type
}
The problem is I'm not able to get item on which the context menu was displayed.
对于这个问题,如果你像这样向ListView
添加数据:
<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>
您可以像这样在 RightTapped
事件中获取项目的上下文:
private void ListView_RightTapped(object sender, RightTappedRoutedEventArgs e)
{
ListView listView = (ListView)sender;
allContactsMenuFlyout.ShowAt(listView, e.GetPosition(listView));
var a = ((FrameworkElement)e.OriginalSource).DataContext;
}
这种场景下,"a"会直接获取点击item的字符串格式内容
如果您像这样使用 DataTemplate
将数据添加到 ListView
:
<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>
通常在使用DataTemplate
时,我们通过ObservableCollection
添加数据,像这样:
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" });
}
"List" class这里很简单,测试一下:
public class List
{
public string text { get; set; }
}
然后我们也可以在RightTapped
事件中得到DataContext
:
private void ListView_RightTapped(object sender, RightTappedRoutedEventArgs e)
{
ListView listView = (ListView)sender;
allContactsMenuFlyout.ShowAt(listView, e.GetPosition(listView));
var a = ((FrameworkElement)e.OriginalSource).DataContext;
}
但是这次"a"实际上是item里面的'List'对象(请参考"List"class),因为item的内容是现在是 'List' 对象,不再是字符串。所以我们可以这样得到这个对象的文本属性:
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;
}
我认为最终你想编辑 Flyout
的 Button click 事件中的内容,你可以这样做,例如:
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 issue is that the context menu is displayed also outside of list view item (e.g. on borders).
你能解释一下吗?我不是很明白。您的意思是在 Flyout
中显示内容?如果是这样,我认为上面的方法可以解决这个问题。如果不行,可以留言,我看看能不能解决这个问题。
And since the event that is triggered is RightTapped, I'm not sure if the context menu would be displayed on long click on mobile devices.
我觉得这里的"long click"事件是指这样的Holding
事件?
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;
}
我刚刚在移动模拟器上测试了它,它工作正常。虽然我在这里写了一个很长的答案,但是关键点很简单,你可以使用 ((FrameworkElement)e.OriginalSource).DataContext
来获取项目的上下文。
在数据模板中添加浮出控件。使用命令来处理事件。 请在此处查看示例代码:
<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>
后面的代码:
private void gridItem_RightTapped(object sender, RightTappedRoutedEventArgs e)
{
FlyoutBase.ShowAttachedFlyout(sender as FrameworkElement);
}
您可以在这里获得完整的解决方案:https://code.msdn.microsoft.com/How-to-implement-flyout-ef52517f