如何从DataGrid的列中获取值?
我正在开发一个WPF应用,并准备将其重构为MVVM模式。我遇到了一个数据网格的问题,它由SQL查询提供数据,在XAML的某一列为每条记录放置了按钮,如下所示:
<DataGrid Name="NestCards" FontSize="12"
ScrollViewer.CanContentScroll="True" MaxHeight="400" ColumnWidth="*">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Click="GetDetails">Details</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
过去我可以直接把sender当作按钮来处理,没问题:
Button pressed = sender as Button;
var nestName = TypeDescriptor.GetProperties(pressed.DataContext)["nestName"].GetValue(pressed.DataContext);
var nestDate = TypeDescriptor.GetProperties(pressed.DataContext)["dueDate"].GetValue(pressed.DataContext);
var orderStatus = TypeDescriptor.GetProperties(pressed.DataContext)["orderStatus"].GetValue(pressed.DataContext);
NestStatus.Text = orderStatus.ToString();
NestName.Text = nestName.ToString();
SchedFor.Text = nestDate.ToString();
我需要获取被点击按钮所在行的至少 NestName 的值,以便把它传给另一条SQL查询,但在MVVM下并不那么直接。
解决方案
在MVVM中,不应该直接从 DataGridColumn 读取值。
一个 DataGrid 只是数据的可视化表示。值应该来自绑定到该行的数据项。
为该行创建一个模型:
public sealed class NestCard
{
public string NestName { get; set; }
public DateTime DueDate { get; set; }
public string OrderStatus { get; set; }
}
将 DataGrid 绑定到ViewModel中的一个集合:
public ObservableCollection<NestCard> NestCards { get; } = new();
然后绑定按钮命令,并把当前行项作为 CommandParameter 传递:
<DataGrid ItemsSource="{Binding NestCards}"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Nest Name"
Binding="{Binding NestName}" />
<DataGridTemplateColumn Header="Details">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Details"
Command="{Binding DataContext.GetDetailsCommand,
RelativeSource={RelativeSource AncestorType=DataGrid}}"
CommandParameter="{Binding}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
使用 RelativeSource 绑定,是因为 Button 位于行模板内。按钮本身的 DataContext 是行项,因此绑定会向上传到父级 DataGrid,通过 DataContext.GetDetailsCommand 来访问ViewModel的命令。
在ViewModel中:
public ICommand GetDetailsCommand { get; }
public MyViewModel()
{
GetDetailsCommand = new RelayCommand<NestCard>(GetDetails);
}
private void GetDetails(NestCard row)
{
if (row is null)
return;
string nestName = row.NestName;
// Use nestName for your next query here.
}
RelayCommand<T> 只是一个示例命令实现。你可以使用你自己的 ICommand 实现,或者来自 CommunityToolkit.Mvvm 的实现。
重要的部分是:
CommandParameter="{Binding}"
在一个 DataGridTemplateColumn.CellTemplate 内,当前的 DataContext 就是行项。因此 {Binding} 将整行对象传递给命令。
这意味着你无需在代码背后访问 DataGrid、列、按钮,或 TextBox.Text。
所以不要这样:
Button pressed = sender as Button;
var nestName = TypeDescriptor.GetProperties(pressed.DataContext)["nestName"].GetValue(...);
改用强类型的行模型:
private void GetDetails(NestCard row)
{
var nestName = row.NestName;
}
这保持了视图负责显示,视图模型负责行为和数据流。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。