WPF 列表视图拖动而不取消选择

发布于 2024-09-10 09:56:40 字数 3415 浏览 2 评论 0原文

我有一个包含程序中文件的列表视图对象。默认的列表视图行为允许我在列表上执行所有选择操作(单击+Shift 选择一个块,单击+Ctrl 单独选择一组项目的成员,然后单击选择单个项目)。

我想通过单击并按住鼠标左键开始拖动这些项目,但它会取消选择这些项目...甚至当鼠标移动时,它也会选择鼠标悬停的任何内容。如何处理鼠标事件以正常允许默认选择,但如果拖动项目则不允许选择/取消选择?

如果我处理向下单击事件,则选择更改会同时发生...只有当单击仍然按下时开始拖动时,我才知道这是拖放与选择更改。

这是控件的基本 XAML...

<Window.Resources>
    <Style x:Key="itemstyle" TargetType="{x:Type ListViewItem}">
        <EventSetter Event="PreviewMouseDown" Handler='listView2_MouseLeftButtonDown'/>
    </Style>
</Window.Resources>


<ListView Grid.Column="0" Grid.Row="1" Name="listView2" Margin="5,5,5,5" BorderBrush="LightGray" AllowDrop="True" Drop="listView2_Drop" ItemsSource="{Binding}" ItemContainerStyle="{StaticResource itemstyle}">
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="Name" Width="100">
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <StackPanel Orientation="Horizontal">
                                        <Image Source="{Binding Bmp}"/>
                                        <TextBlock Text="{Binding Name}"/>
                                    </StackPanel>
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                        <GridViewColumn Header="Ext" DisplayMemberBinding="{Binding Ext}" Width="Auto"/>
                        <GridViewColumn Header="Size" DisplayMemberBinding="{Binding Size}" Width="Auto"/>
                        <GridViewColumn Header="Date" DisplayMemberBinding="{Binding Date}" Width="Auto"/>
                    </GridView>
                </ListView.View>
            </ListView>

好吧,我已经处理了 PreviewMouseDown 和 Preview Mouse Up 事件...如果按下 Control 键或 Shift 键,我不会设置句柄标志。 . 但否则我将已处理的参数设置为 true (因此不会发生选择更改)然后在 Previewmouseup 事件中,我通过将“选定”值设置为 true (同样仅当按下 Shift 或 Ctrl 时)来完成单选择。所以这有点工作......但是shift-block-selection不使用我以编程方式选择的任何项目作为选择的有效起点,而是转到使用shift或ctrl键单击的第一个项目(即使我'已手动清除所有选定的项目)。

这是来源:

private void listView2_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            if (!Keyboard.IsKeyDown(Key.LeftCtrl) &&
               !Keyboard.IsKeyDown(Key.RightCtrl) &&
               !Keyboard.IsKeyDown(Key.LeftShift) &&
               !Keyboard.IsKeyDown(Key.RightShift))
            {
                e.Handled = true;
            }
        }
    }

    private void listView2_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        if (e.ChangedButton == MouseButton.Left)
        {
            if (!Keyboard.IsKeyDown(Key.LeftCtrl) &&
               !Keyboard.IsKeyDown(Key.RightCtrl) &&
               !Keyboard.IsKeyDown(Key.LeftShift) &&
               !Keyboard.IsKeyDown(Key.RightShift))
            {

                listView2.SelectedItems.Clear();
                ListViewItem lvi = sender as ListViewItem;
                listView2.SelectedItem = lvi;
                lvi.IsSelected = true;
                e.Handled = true;
            }
        }
    }

I have a listview object containing files in the program. The default listview behavior allows me to do all the select operations on the list (click+shift to select a block, click+ctrl for individually selecting members of a group of items, and click to select a single item).

I want to begin dragging these items with a click and hold of the left mouse button, but it deselects the items... and even as the mouse moves, it will select whatever the mouse is over. How do I handle the mouse events to allow default selection normally, but no select/deselect if the item is being dragged?

If I handle the down click event, the selection change happens at the same time... its only when a drag starts while the click is still down that I know that it is a drag and drop vs a selection change.

Here is the basic XAML for the control...

<Window.Resources>
    <Style x:Key="itemstyle" TargetType="{x:Type ListViewItem}">
        <EventSetter Event="PreviewMouseDown" Handler='listView2_MouseLeftButtonDown'/>
    </Style>
</Window.Resources>


<ListView Grid.Column="0" Grid.Row="1" Name="listView2" Margin="5,5,5,5" BorderBrush="LightGray" AllowDrop="True" Drop="listView2_Drop" ItemsSource="{Binding}" ItemContainerStyle="{StaticResource itemstyle}">
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="Name" Width="100">
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <StackPanel Orientation="Horizontal">
                                        <Image Source="{Binding Bmp}"/>
                                        <TextBlock Text="{Binding Name}"/>
                                    </StackPanel>
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                        <GridViewColumn Header="Ext" DisplayMemberBinding="{Binding Ext}" Width="Auto"/>
                        <GridViewColumn Header="Size" DisplayMemberBinding="{Binding Size}" Width="Auto"/>
                        <GridViewColumn Header="Date" DisplayMemberBinding="{Binding Date}" Width="Auto"/>
                    </GridView>
                </ListView.View>
            </ListView>

Ok, so I've gone with handling the previewmousedown and preview mouse up events... if a control key or shift key is pressed, I don't set the handle flag... but otherwise I set the handled argument to true (so selection changes don't happen) Then on the previewmouseup event, I complete the single selection by setting the "selected" value to true (again only when shift or ctrl is pressed). So this kinda works... but the shift-block-selection doesn't use any item I select programatically as a valid starting point for the select, instead going to the first item clicked using a shift or ctrl key (even if I've cleared all the selected items manually).

Here is the source:

private void listView2_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            if (!Keyboard.IsKeyDown(Key.LeftCtrl) &&
               !Keyboard.IsKeyDown(Key.RightCtrl) &&
               !Keyboard.IsKeyDown(Key.LeftShift) &&
               !Keyboard.IsKeyDown(Key.RightShift))
            {
                e.Handled = true;
            }
        }
    }

    private void listView2_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        if (e.ChangedButton == MouseButton.Left)
        {
            if (!Keyboard.IsKeyDown(Key.LeftCtrl) &&
               !Keyboard.IsKeyDown(Key.RightCtrl) &&
               !Keyboard.IsKeyDown(Key.LeftShift) &&
               !Keyboard.IsKeyDown(Key.RightShift))
            {

                listView2.SelectedItems.Clear();
                ListViewItem lvi = sender as ListViewItem;
                listView2.SelectedItem = lvi;
                lvi.IsSelected = true;
                e.Handled = true;
            }
        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

眼眸 2024-09-17 09:56:40

不久前,TreeView 控件也遇到了同样的问题...这是我解决该问题的方法:

private void TreeViewItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    // skip mouse clicks on the expander button
    if (e.Source is ToggleButton)
        return;

    // find the original source's parent TreeViewItem
    DependencyObject originalSource = e.OriginalSource as DependencyObject;
    while (originalSource != null)
    {
        TreeViewItem tvi = originalSource as TreeViewItem;
        if (tvi != null)
        {
            IListItem listItem = tvi.Header as IListItem;
            if (listItem != null)
            {
                if (Keyboard.Modifiers == ModifierKeys.Shift)
                    ViewModel.MultiSelectTo(listItem);
                else if (Keyboard.Modifiers == ModifierKeys.Control)
                    ViewModel.ToggleSelection(listItem);
                else
                    ViewModel.Select(listItem);
            }

            // the TreeViewItem is never truly selected... when selected, we manually change it's background color (see xaml)
            tvi.IsSelected = false;
            e.Handled = true;
            break;
        }

        originalSource = VisualTreeHelper.GetParent(originalSource);
    }
}

XAML:

<Style.Triggers>
<DataTrigger Binding="{Binding Selected}" Value="True">
    <Setter Property="Background" Value="#FF3399FF" />
</DataTrigger>
</Style.Triggers>

IListItem 接口是我的数据对象实现的接口,以便在我的 TreeView 中显示。
ViewModel 属性是我的视图DataContext
另外,以下注释很重要“TreeViewItem 从未真正被选择...选择时,我们手动更改其背景颜色(请参阅 xaml)”。

所以基本上,我所做的就是从 TreeView 控件中删除选择处理,以便自己处理。

希望这能以任何方式帮助...

Had the same issue with the TreeView control not long ago... here's how I worked around the issue:

private void TreeViewItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    // skip mouse clicks on the expander button
    if (e.Source is ToggleButton)
        return;

    // find the original source's parent TreeViewItem
    DependencyObject originalSource = e.OriginalSource as DependencyObject;
    while (originalSource != null)
    {
        TreeViewItem tvi = originalSource as TreeViewItem;
        if (tvi != null)
        {
            IListItem listItem = tvi.Header as IListItem;
            if (listItem != null)
            {
                if (Keyboard.Modifiers == ModifierKeys.Shift)
                    ViewModel.MultiSelectTo(listItem);
                else if (Keyboard.Modifiers == ModifierKeys.Control)
                    ViewModel.ToggleSelection(listItem);
                else
                    ViewModel.Select(listItem);
            }

            // the TreeViewItem is never truly selected... when selected, we manually change it's background color (see xaml)
            tvi.IsSelected = false;
            e.Handled = true;
            break;
        }

        originalSource = VisualTreeHelper.GetParent(originalSource);
    }
}

XAML:

<Style.Triggers>
<DataTrigger Binding="{Binding Selected}" Value="True">
    <Setter Property="Background" Value="#FF3399FF" />
</DataTrigger>
</Style.Triggers>

The IListItem interface is the interface that my data objects implements in order to be shown in my TreeView.
The ViewModel property is my view DataContext.
Also, the following comment is important "the TreeViewItem is never truly selected... when selected, we manually change it's background color (see xaml)".

So basically, what I did, is remove the selection handling from the TreeView control to handle it myself.

Hope this helps in any way...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文