我有一个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中的datacontext是错误的,但我不知道如何纠正它,也不知道如何传递按钮按下的特定行。感谢收到任何和所有建议,以帮助我连接我的嵌入式按钮!
答案 0 :(得分:29)
这会对你有所帮助
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<Button
Command="{Binding Path=DataContext.showCustomerCommand,
RelativeSource= {RelativeSource FindAncestor,
AncestorType={x:Type DataGrid}}}">
</Button>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
答案 1 :(得分:6)
This问题/答案与您正在寻找的内容类似。
您可以将行的ID绑定到命令参数
<Button Click="Button_Click" Command="{Binding showCustomerCommand}"
CommandParameter="{Binding Path=ID}">View Details</Button>
答案 2 :(得分:2)
<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>
内的Resharper / Intellisense推理不正确。
这可能会引起混淆,为了纠正这个问题,DataTemplate应该有一个显式的DataType引用该行绑定的类型。
我找到了两种方法来解决你的问题,使用命令的相对绑定,以便它使用DataGrid的Context而不是当前行绑定,或者在一个元素上创建一个x:Name属性你希望绑定的上下文。
我相信如果你试图访问一个祖先,相对绑定会更清晰,但是如果你需要绑定到树中其他地方的东西,那么ElementName就可以允许它。
XAML:
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());
}
}
}
类别:
@FunctionalInterface