UWP ListView项上下文菜单

9
我正在搜索如何为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项目创建上下文菜单。

3个回答

20

问题是我无法获取显示上下文菜单的项目。

对于这个问题,如果您像这样向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”将直接获取所点击项的字符串格式内容。
如果您使用如下所示的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”类是很简单的测试类:

"
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”实际上是项目内的“List”对象(请参见“List”类),因为项目的内容现在是一个“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 的按钮单击事件中编辑内容,你可以像这样做:

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 = "";
}

另一个问题是,上下文菜单也会显示在列表视图项之外(例如在边框上)。

您能解释一下吗?我不太理解。您是指将内容显示在Flyout中吗?如果是这样,我认为上述方法可以解决此问题。如果不是,请留下评论,我会看看是否能解决此问题。

由于触发的事件是RightTapped,我不确定在移动设备上长按是否会显示上下文菜单。

我认为这里的“长按”事件指的是像这样的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即可获取项目的上下文。


3

使用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
}

谢谢回复。我会尝试这个方法。但是触发此操作的事件仍然为在列表视图上右键单击。因此,当我在列表视图中右键单击组标题或边框时,它将被触发。我一直期望着实现起来非常容易,因为这是常见的功能。 - miskohut
绑定是有意义的,但它总是null。一直没有成功将Command属性附加到任何东西上。 - escape-llc
尝试使用来自Prism框架的“Behaviors”和“InvokeCommandAction”。 - Archana

1
在数据模板中添加flyout。使用命令来处理事件。 请参见以下示例代码:
<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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接