【问题标题】:ListView, Select Item before ContextFlyout opens or Item is draggedListView,在 ContextFlyout 打开或拖动项目之前选择项目
【发布时间】:2021-05-12 09:21:55
【问题描述】:

我有一个带有上下文菜单的 ListView,可以重新排序。 我希望它的行为非常类似于 power-point 演示文稿(以及许多其他应用程序)中的缩略图:

  • 如果您在尚未选择的页面上单击鼠标右键,则在弹出上下文菜单之前它成为已选择的页面
  • 如果您开始拖动尚未选中的页面,则该页面在拖动前成为选中页面。

Xaml:

<Page
    x:Class="TestApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:TestApp"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Page.Resources>
        <MenuFlyout x:Key="EditFlyout">
            <MenuFlyoutItem Text="Copy" Icon="Copy"/>
            <MenuFlyoutItem Text="Paste" Icon="Paste"/>
        </MenuFlyout>
    </Page.Resources>
    
    <Grid>
        <ListView
            ItemsSource="{x:Bind Pages, Mode=OneWay}"
            SelectionMode="Extended"
            CanReorderItems="True" AllowDrop="True"
            ContextFlyout="{StaticResource EditFlyout}">
            <ListView.ItemTemplate>
                <DataTemplate x:DataType="local:DocPage">
                    <TextBlock Text="{x:Bind Name, Mode=OneWay}"/>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

    </Grid>
</Page>

代码:

namespace TestApp
{
        public class DocPage
        {
            public string Name;
            // Edit: actual class is more complex and includes rendered bitmap thumbnail etc...
        }
    
        public sealed partial class MainPage : Windows.UI.Xaml.Controls.Page
        {
            public ObservableCollection<DocPage> Pages = new ObservableCollection<DocPage>();
    
            public MainPage()
            {
                this.InitializeComponent();
                DocPage PageA = new DocPage() { Name = "PageA" };
                DocPage PageB = new DocPage() { Name = "PageB" };
                Pages.Add(PageA);
                Pages.Add(PageB); // duplicates are intended, we cannot differentiale a selection by "item"
                Pages.Add(PageB);
                Pages.Add(PageA); 
                Pages.Add(PageB);
                Pages.Add(PageB);
            }
        }
    }

我怎样才能做到这一点?

编辑:满足预期行为的一种方法是在按下项目而不是释放项目时触发选择/多选(使用 ctrl / shift)的 ListView 逻辑。显然在 WPF 上,选择逻辑在按下项目时发生,但在 UWP 中,当项目被释放时发生,不知道为什么(link

【问题讨论】:

    标签: uwp


    【解决方案1】:

    如果你在一个还没有被选中的页面上右击,那么它在上下文菜单弹出之前就变成了选中的页面

    对于这个场景,你可以监听ListViewRightTapped事件,它会在菜单弹出时执行,你可以获取当前点击的item并传递给ListView的Selecteditem

    private void MyListView_RightTapped(object sender, RightTappedRoutedEventArgs e)
    {
            ListView listView = (ListView)sender;
    
    
    
            DocPage targetItem = ((FrameworkElement)e.OriginalSource).DataContext as DocPage;
    
    
    
            var index = Pages.IndexOf(targetItem);
            if (index >= 1 && index < Pages.Count)
            {
                MyListView.SelectedIndex = index;
            }
           
     }
    

    如果你开始拖动一个尚未被选中的页面,那么它在拖动之前成为选中的页面。

    当你拖拽listview item时,它会调用DragItemsStarting事件,对于这种场景,请获取拖拽item并使其处于选中状态。

    private void ListView_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
    {
        // The ListView is declared with selection mode set to Single.
        // But we want the code to be robust
        if (e.Items.Count == 1)
        {
            DocPage targetItem = e.Items[0] as DocPage;
    
    
    
            var index = Pages.IndexOf(targetItem);
    
    
    
            if (index >= 1 && index < Pages.Count)
            {
                MyListView.SelectedIndex = index;
            }
    
    
    
        }
    }
    

    有意重复,我们无法通过“项目”区分选择

    我们建议您使用具有特定它的类实例来替换普通值作为列表视图项。

    Xaml 代码

     <ListView
                x:Name="MyListView"
                ItemsSource="{x:Bind Pages, Mode=OneWay}"
                SelectionMode="Extended"
                CanReorderItems="True" AllowDrop="True"
                RightTapped="MyListView_RightTapped"
                CanDragItems="True"
                DragItemsStarting="ListView_DragItemsStarting"
                ContextFlyout="{StaticResource EditFlyout}">
               
                <ListView.ItemTemplate>
                    <DataTemplate x:DataType="local:DocPage">
                        <TextBlock Text="{x:Bind Name, Mode=OneWay}" />
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
    

    【讨论】:

    • 谢谢尼科。我猜你ment index >= 0 并且应该删除“// ListView 被声明为选择模式设置为Single。”在答案中。
    • 以下是我在提出的解决方案中看到的问题:对于“重复是有意的,我们不能按项目区分选择”,我不明白你的答案。实际的类比示例中的更复杂,所以我不想复制实例,并且 IndexOf 解决方案不起作用。对于解决方案,我非常希望在第一次点击时触发选择,而不是在拖动开始时触发。我想知道是否可以通过听一些 Itemcontainer 事件来解决所有 3 个问题。
    • 我的意思是,你需要用特定的id创建类实例,并用id查询它。
    猜你喜欢
    • 2020-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多