Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF listview drag without deselect

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;
            }
        }
    }
like image 307
tbischel Avatar asked Nov 15 '22 09:11

tbischel


1 Answers

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...

like image 81
SuperOli Avatar answered Dec 05 '22 02:12

SuperOli