Множественный выбор WPF Datagrid без CTRL или пробела
в WPF Datagrid есть два режима выбора: одиночный или расширенный. WPF ListView имеет третье-несколько. Этот режим позволяет щелкнуть и выбрать несколько строк без удержания CTRL или Shift. Кто-нибудь знает, как это сделать для datagrid?
4 ответов
Это не поддерживается в DataGrid в toolkit, и похоже, что это Не поддерживается когда DataGrid поставляется с .NET 4 либо. Еще одна причина, почему этот контроль не готов к использованию в производстве. Я бы с одним из этих вариантов:
- сверните свою собственную сетку с помощью ListView / GridView
- измените исходный код DataGrid в toolkit (это не должно быть слишком сложно, так как расширенный выбор уже поддерживается?)
- ищите любой из коммерческих доступных WPF DataGrids (они обычно добавляют огромное количество полезных функций)
Я согласен, что DataGrid должен поддерживать это, и я думаю, что вы должны файл ошибка / предложение для этого в любом случае. Возможно, еще не поздно получить его в .NET 4.. :)
Я создавал приложение с аналогичным требованием, которое будет работать как для сенсорного экрана и рабочего стола. Потратив на это некоторое время, решение, которое я придумал, кажется чище. В конструкторе я добавил в datagrid следующие задатчики событий:
<DataGrid.RowStyle>
<Style TargetType="DataGridRow" >
<EventSetter Event="MouseEnter" Handler="MouseEnterHandler"></EventSetter>
<EventSetter Event="PreviewMouseDown" Handler="PreviewMouseDownHandler"></EventSetter>
</Style>
</DataGrid.RowStyle>
затем в codebehind я обработал события как:
private void PreviewMouseDownHandler(object sender, MouseButtonEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
DataGridRow row = Utility.GetVisualParentByType(
(FrameworkElement)e.OriginalSource, typeof(DataGridRow)) as DataGridRow;
row.IsSelected = !row.IsSelected;
e.Handled = true;
}
}
private void MouseEnterHandler(object sender, MouseEventArgs e)
{
if (e.OriginalSource is DataGridRow && e.LeftButton == MouseButtonState.Pressed)
{
DataGridRow row = e.OriginalSource as DataGridRow;
row.IsSelected = !row.IsSelected;
e.Handled = true;
}
}
вот код для вспомогательного метода GetVisualParentByType:
public static DependencyObject GetVisualParentByType(DependencyObject startObject, Type type)
{
DependencyObject parent = startObject;
while (parent != null)
{
if (type.IsInstanceOfType(parent))
break;
else
parent = VisualTreeHelper.GetParent(parent);
}
return parent;
}
надеюсь, это поможет кому-то еще.
вы можете попробовать этот простой обходной путь без необходимости изменения / наследования DataGrid
управление путем обработки события предварительного просмотра мыши вниз следующим образом:
TheDataGrid.PreviewMouseLeftButtonDown +=
new MouseButtonEventHandler(TheDataGrid_PreviewMouseLeftButtonDown);
void TheDataGrid_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// get the DataGridRow at the clicked point
var o = TryFindFromPoint<DataGridRow>(TheDataGrid, e.GetPosition(TheDataGrid));
// only handle this when Ctrl or Shift not pressed
ModifierKeys mods = Keyboard.PrimaryDevice.Modifiers;
if (o != null && ((int)(mods & ModifierKeys.Control) == 0 &&
(int)(mods & ModifierKeys.Shift) == 0))
{
o.IsSelected = !o.IsSelected;
e.Handled = true;
}
}
public static T TryFindFromPoint<T>(UIElement reference, Point point)
where T:DependencyObject
{
DependencyObject element = reference.InputHitTest(point) as DependencyObject;
if (element == null)
return null;
else if (element is T)
return (T)element;
else return TryFindParent<T>(element);
}
на TryFindFromPoint
способ, с блоге Суми Филипп, используется для получения DataGridRow
экземпляр с точки.
при проверке ModifierKeys
, вы все еще можете сохранить Ctrl и Shift в качестве поведения по умолчанию.
только один отход от этого метода заключается в том, что вы не можете щелкнуть и перетащить в выполните выбор диапазона, как он может первоначально.
на основе предыдущей статьи я написал ("like") код MVVM:
Сначала добавьте это в свой основной вид:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
соответствующая часть вид:
<DataGrid
Style="{StaticResource DataGridStyle}"
ItemsSource="{Binding Results}"
SelectionUnit="FullRow"
SnapsToDevicePixels="True"
SelectionMode="Extended"> <!--You can change selection mode with converter. It will work (i tested it.)-->
<i:Interaction.Behaviors>
<utils:EventToCommandBehavior Command="{Binding TouchCommand}"
Event="PreviewTouchDown"
PassArguments="True"></utils:EventToCommandBehavior>
<utils:EventToCommandBehavior Command="{Binding MouseCommand}"
Event="PreviewMouseDown"
PassArguments="True"></utils:EventToCommandBehavior>
</i:Interaction.Behaviors>
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="IsSelected"<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush>
<SolidColorBrush.Color>
<Color A="50" R="0" G="0" B="0" />
</SolidColorBrush.Color>
</SolidColorBrush>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<!-- your columns -->
</DataGrid.Columns>
</DataGrid>
дополнительная информация о EventToCommandBehavior: здесь
таким образом, ваша ViewModel должна реализовать следующие команды:
//i skipped the TouchCommand definition because MouseCommand runs for touch on screen too.
public RelayCommand<MouseButtonEventArgs> MouseCommand
{
get
{
return new RelayCommand<MouseButtonEventArgs>((e)=> {
if (e.LeftButton == MouseButtonState.Pressed)
{
//call this function from your utils/models
var row = FindTemplatedParentByVisualParent<DataGridRow>((FrameworkElement)e.OriginalSource,typeof(ICommandSource));
//add ICommanSource to parameters. (if actual cell contains button instead of data.) Its optional.
if(row!=null)
{
row.IsSelected = !row.IsSelected;
e.Handled = true;
}
}
});
}
}
наконец-то реализовать метод (где-то в модели), чтобы найти строку ().
public static T FindTemplatedParentByVisualParent<T>(FrameworkElement element,Type exceptionType = null) where T : class
{
if (element != null && (exceptionType == null || element.TemplatedParent == null || (exceptionType != null && element.TemplatedParent !=null && !exceptionType.IsAssignableFrom(element.TemplatedParent.GetType()))))
{
Type type = typeof(T);
if (type.IsInstanceOfType(element.TemplatedParent))
{
return (element.TemplatedParent as T);
}
else
{
return FindTemplatedParentByVisualParent<T>((FrameworkElement)VisualTreeHelper.GetParent(element));
}
}
else
return null;
}
это решение работает для меня отлично, поэтому я надеюсь, что это поможет и вам.