从 WPF DataGrid 中的按钮触发 RelayCommand
Posted
技术标签:
【中文标题】从 WPF DataGrid 中的按钮触发 RelayCommand【英文标题】:Firing a RelayCommand from a button inside a WPF DataGrid 【发布时间】:2012-08-24 04:01:23 【问题描述】:我有一个DataGrid
显示在 XAML 中定义的客户列表,如下绑定到我的 ViewModel:
<DataGrid Name="CustomersDataGrid" ItemsSource="Binding Customers">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Command="Binding showCustomerCommand"
Content="Binding Path=Name"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
网格的显示工作正常。我希望能够显示单个客户的详细信息。以前,我为所选行设置了绑定,并在页面上有一个按钮,该按钮绑定到以下命令:
RelayCommand _showCustomerCommand;
public ICommand showCustomerCommand
get
if (_showCustomerCommand == null)
_showCustomerCommand = new RelayCommand(param => this.ShowCustomer());
return _showCustomerCommand;
private void ShowCustomer()
if (Parent != null)
// Handle Customer Display Here
这很好用。但我希望能够单击单个行内的按钮,而不是基于选定行的单个按钮。我知道上述 XAML 中的数据上下文是错误的,但我不知道如何纠正它,也不知道如何传递按钮按下的特定行。任何和所有帮助我连接嵌入式按钮的建议都非常感谢!
【问题讨论】:
嘿,我知道我在这里有点挖坟,但是您找到解决这种情况的方法了吗?我正在尝试完成同样的事情。 【参考方案1】:这对你有帮助
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<Button
Command="Binding Path=DataContext.showCustomerCommand,
RelativeSource= RelativeSource FindAncestor,
AncestorType=x:Type DataGrid">
</Button>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
【讨论】:
【参考方案2】:This 问题/答案与您要查找的内容相似。
可以将行的ID绑定到命令参数
<Button Click="Button_Click" Command="Binding showCustomerCommand"
CommandParameter="Binding Path=ID">View Details</Button>
【讨论】:
它是相似的,但它与背后的常规代码有关,而不是我尝试使用的 MVVM 模式。不过谢谢! 请仔细阅读答案。另外,在我的回答中,我给了你 MVVM 方式。您的绑定保持不变,但现在您可以在命令中使用一个参数。 我明白了;谢谢。但是,根据我的问题标题,我正在寻找有关如何将其与中继命令一起使用的指导。简而言之,我希望得到一个更详细的答案。【参考方案3】:DataGridTemplate
内部的 Resharper/Intellisense 推断不正确。
这可能会导致混淆,为了纠正这种情况,DataTemplate 应该有一个明确的 DataType 引用该行绑定到的类型。
我发现有 2 种方法可以解决您的问题,使用相对绑定命令,以便它使用 DataGrid 的上下文进行绑定,而不是当前行,或者在具有的元素上创建 x:Name 属性您希望绑定到的上下文。
我相信,如果您尝试访问祖先,则相对绑定会更清晰,但如果您需要绑定到树中其他地方的某些东西,那么 ElementName 可能会允许这样做。
XAML:
<Window x:Class="TestBindings.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TestBindings"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:WindowViewModel/>
</Window.DataContext>
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<GroupBox x:Name="Test" Header="Grid" Grid.Column="0"> <!-- #2 Add a name to the element you need to bind to. -->
<DataGrid ItemsSource="Binding RowList" IsSynchronizedWithCurrentItem="True" SelectionUnit="FullRow" >
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="local:RowViewModel"><!-- Needed for correct inference in XAML editor -->
<!-- #1 Cleaner solution as it doesn't depend on names -->
<Button Content="Binding Path=RowCount" Command="Binding Path=DataContext.NineCommand, RelativeSource=RelativeSource AncestorType=x:Type DataGrid" CommandParameter="Binding" />
<!-- #2 Naming the element explicitly probably allows you to jump elsewhere in the tree -->
<Button Content="Binding Path=RowCount" Command="Binding Path=DataContext.NineCommand, ElementName=Test" CommandParameter="Binding" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</GroupBox>
<GroupBox Header="Binding Path=SelectedRow.RowCount" Grid.Column="1">
<Label Content="Binding Path=RowList/RowCount"></Label>
</GroupBox>
</Grid>
</Window>
类:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Data;
using System.Windows.Input;
using Microsoft.Expression.Interactivity.Core;
using Microsoft.Practices.Prism.ViewModel;
namespace TestBindings
public class RowViewModel : NotificationObject
private static int _max = 0;
private int _rowCount;
public int RowCount
get return _rowCount;
set
if (_rowCount == value) return;
_rowCount = value;
RaisePropertyChanged(nameof(RowCount));
public RowViewModel()
_rowCount = _max++;
public class TypedCommand<T> : ICommand
private readonly Predicate<T> _canExecute;
private readonly Action<T> _execute;
public TypedCommand(Action<T> execute, Predicate<T> canExecute = null)
this._canExecute = canExecute;
this._execute = execute;
public bool CanExecute(object parameter)
return _canExecute == null || _canExecute((T) parameter);
public void Execute(object parameter)
_execute?.Invoke((T) parameter);
public event EventHandler CanExecuteChanged;
public class WindowViewModel : NotificationObject
public ObservableCollection<RowViewModel> RowList get; = new ObservableCollection<RowViewModel>();
private RowViewModel _selectedRow;
public RowViewModel SelectedRow
get return _selectedRow;
private set
if (_selectedRow == value) return;
_selectedRow = value;
RaisePropertyChanged(nameof(SelectedRow));
private static readonly Action<RowViewModel> DeleteAction = new Action<RowViewModel>(row => row.RowCount=99);
public ICommand NineCommand get; = new TypedCommand<RowViewModel>(DeleteAction);
public WindowViewModel()
//0
RowList.Add(new RowViewModel());
//1
RowList.Add(new RowViewModel());
//2
RowList.Add(new RowViewModel());
【讨论】:
以上是关于从 WPF DataGrid 中的按钮触发 RelayCommand的主要内容,如果未能解决你的问题,请参考以下文章
WPF datagrid按钮列点击如何获取当前行某单元格的值!