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;
}
}
开发者_运维问答 }
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...
精彩评论