Связывание команды DoubleClick из строки DataGrid в VM
У меня есть Datagrid и мне не нравится мой метод обхода для запуска команды двойного щелчка на моей модели просмотра для выбранной (выбранной) строки.
Вид:
<DataGrid EnableRowVirtualization="True"
ItemsSource="{Binding SearchItems}"
SelectedItem="{Binding SelectedItem}"
SelectionMode="Single"
SelectionUnit="FullRow">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<cmd:EventToCommand Command="{Binding MouseDoubleClickCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
...
</DataGrid>
ViewModel:
public ICommand MouseDoubleClickCommand
{
get
{
if (mouseDoubleClickCommand == null)
{
mouseDoubleClickCommand = new RelayCommand<MouseButtonEventArgs>(
args =>
{
var sender = args.OriginalSource as DependencyObject;
if (sender == null)
{
return;
}
var ancestor = VisualTreeHelpers.FindAncestor<DataGridRow>(sender);
if (ancestor != null)
{
MessengerInstance.Send(new FindDetailsMessage(this, SelectedItem.Name, false));
}
}
);
}
return mouseDoubleClickCommand;
}
}
Я хочу избавиться от кода, связанного с представлением (с объектом зависимостей и помощником визуального дерева) в моей модели просмотра, так как это как-то нарушает возможности тестирования. Но, с другой стороны, я избегаю того, что что-то происходит, когда пользователь не нажимает на строку, но, например, на заголовок.
PS: Я попытался взглянуть на приложенное поведение, но я не могу загрузить с Skydrive на работе, поэтому лучше было бы использовать встроенное решение.
Ответы
Ответ 1
Почему бы вам просто не использовать CommandParameter
?
<DataGrid x:Name="myGrd"
ItemsSource="{Binding SearchItems}"
SelectedItem="{Binding SelectedItem}"
SelectionMode="Single"
SelectionUnit="FullRow">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<cmd:EventToCommand Command="{Binding MouseDoubleClickCommand}"
CommandParameter="{Binding ElementName=myGrd, Path=SelectedItem}" />
</i:EventTrigger>
</i:Interaction.Triggers>
...
</DataGrid>
Ваша команда выглядит примерно так:
public ICommand MouseDoubleClickCommand
{
get
{
if (mouseDoubleClickCommand == null)
{
mouseDoubleClickCommand = new RelayCommand<SearchItem>(
item =>
{
var selectedItem = item;
});
}
return mouseDoubleClickCommand;
}
}
EDIT: теперь я использую это вместо Interaction.Triggers
:
<DataGrid.InputBindings>
<MouseBinding MouseAction="LeftDoubleClick"
Command="{Binding Path=MouseDoubleClickCommand}"
CommandParameter="{Binding ElementName=myGrd, Path=SelectedItem}" />
</DataGrid.InputBindings>
Ответ 2
Вот как вы могли реализовать его с помощью приложенного поведения:
EDIT: Теперь регистрирует поведение на DataGridRow
, а не DataGrid
, так что DataGridHeader
клики игнорируются.
Поведение:
public class Behaviours
{
public static DependencyProperty DoubleClickCommandProperty =
DependencyProperty.RegisterAttached("DoubleClickCommand", typeof(ICommand), typeof(Behaviours),
new PropertyMetadata(DoubleClick_PropertyChanged));
public static void SetDoubleClickCommand(UIElement element, ICommand value)
{
element.SetValue(DoubleClickCommandProperty, value);
}
public static ICommand GetDoubleClickCommand(UIElement element)
{
return (ICommand)element.GetValue(DoubleClickCommandProperty);
}
private static void DoubleClick_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var row = d as DataGridRow;
if (row == null) return;
if (e.NewValue != null)
{
row.AddHandler(DataGridRow.MouseDoubleClickEvent, new RoutedEventHandler(DataGrid_MouseDoubleClick));
}
else
{
row.RemoveHandler(DataGridRow.MouseDoubleClickEvent, new RoutedEventHandler(DataGrid_MouseDoubleClick));
}
}
private static void DataGrid_MouseDoubleClick(object sender, RoutedEventArgs e)
{
var row= sender as DataGridRow;
if (row!= null)
{
var cmd = GetDoubleClickCommand(row);
if (cmd.CanExecute(row.Item))
cmd.Execute(row.Item);
}
}
}
Xaml:
<DataGrid x:Name="grid" EnableRowVirtualization="True"
SelectedItem="{Binding SelectedItem}"
SelectionMode="Single"
SelectionUnit="FullRow" ItemsSource="{Binding SearchItems}">
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="Behaviours.DoubleClickCommand" Value="{Binding ElementName=grid, Path=DataContext.SortStateCommand}"/>
</Style>
</DataGrid.RowStyle>
Затем вам необходимо изменить свой MouseDoubleClickCommand
, чтобы удалить параметр MouseButtonEventArgs
и заменить его на свой тип SelectedItem
.
Ответ 3
Проще, чем любое из предлагаемых здесь решений.
Я использую этот.
<!--
requires IsSynchronizedWithCurrentItem
for more info on virtualization/perf https://stackoverflow.com/questions/9949358/datagrid-row-virtualization-display-issue
-->
<DataGrid ItemsSource="{Binding SearchItems}"
IsSynchronizedWithCurrentItem="True"
AutoGenerateColumns="false" CanUserAddRows="False" CanUserDeleteRows="False" IsReadOnly="True" EnableRowVirtualization="True"
>
<!-- for details on ICollection view (the magic behind {Binding Accounts/} https://marlongrech.wordpress.com/2008/11/22/icollectionview-explained/ -->
<DataGrid.InputBindings>
<MouseBinding
MouseAction="LeftDoubleClick"
Command="{Binding MouseDoubleClickCommand}"
CommandParameter="{Binding SearchItems/}" />
</DataGrid.InputBindings>
</DataGrid>
from WPF DataGrid: CommandBinding для двойного клика вместо использования событий
Ответ 4
Вы можете попробовать обходное решение:
<DataGrid EnableRowVirtualization="True"
ItemsSource="{Binding SearchItems}"
SelectedItem="{Binding SelectedItem}"
SelectionMode="Single"
SelectionUnit="FullRow">
<DataGrid.Columns>
<DataGridTemplateColumn Header=".....">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock .....>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<cmd:EventToCommand Command="{Binding MouseDoubleClickCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</DataTemplate>
...................
В этом случае вам нужно указать DataTemplate
для каждого столбца в DataGrid