使用 TemplateColumns 将 WPF DataGrid 绑定到 DataTable

问题描述 投票:0回答:3

我已经尝试了一切但一无所获,所以我希望有人能给我一个顿悟的时刻。 我根本无法获得绑定来成功提取数据网格中的数据。

我有一个包含 MyDataType 的多列的 DataTable

public class MyData
{
    string nameData {get;set;}
    bool showData {get;set;}
}

MyDataType 有 2 个属性(一个字符串,一个布尔值) 我创建了一个测试数据表

DataTable GetDummyData()
{
    DataTable dt = new DataTable("Foo");
    dt.Columns.Add(new DataColumn("AnotherColumn", typeof(MyData)));
    dt.Rows.Add(new MyData("Row1C1", true));
    dt.Rows.Add(new MyData("Row2C1", false));
    dt.AcceptChanges();
    return dt;
}

我有一个 WPF DataGrid,我想显示我的数据表。 但我想要做的就是更改每个单元格的呈现方式,以显示每个单元格的 [TextBlock][Button] 以及绑定到 MyData 对象的值,这就是我遇到很多麻烦的地方。

我的 XAML 看起来像这样

<Window.Resources>
    <ResourceDictionary>
        <DataTemplate x:Key="MyDataTemplate" DataType="MyData">
            <StackPanel Orientation="Horizontal" >
                <Button Background="Green" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="5,0,0,0" Content="{Binding Path=nameData}"></Button>
                <TextBlock Background="Green" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,0,0" Text="{Binding Path=nameData}"></TextBlock>
            </StackPanel>
        </DataTemplate>
    </ResourceDictionary>
</Window.Resources>
<Grid>
    <dg:DataGrid Grid.Row="1" ItemsSource="{Binding}" AutoGenerateColumns="True"
                 x:Name="dataGrid1" SelectionMode="Single" CanUserAddRows="False"
                 CanUserSortColumns="true" CanUserDeleteRows="False" AlternatingRowBackground="AliceBlue"
                 AutoGeneratingColumn="dataGrid1_AutoGeneratingColumn" />
</Grid>

现在加载后我所做的就是尝试将 DataTable 绑定到 WPF DataGrid

dt = GetDummyData();
dataGrid1.ItemsSource = dt.DefaultView;

TextBlock 和 Button 显示,但它们没有绑定,这使得它们为空。 如果有人知道如何解决这个问题,可以告诉我吗? 这应该很简单,这就是微软让我们相信的。 我在

Column.CellTemplate
事件期间设置了
AutoGenerating
,但仍然没有绑定。

请帮忙!!!

wpf data-binding binding datagrid datatable
3个回答
16
投票

编辑:更新以反映 Aran Mulholland 的输入(参见评论)

显然

DataGrid
正在将整个
DataRowView
传递给每个单元格。这就是绑定不起作用的原因。您的
DataTemplate
希望
DataContext
的类型为
MyData
,但实际上它的类型为
DataRowView
。我建议的(有点黑客式的)解决方法是创建一个自定义的
DataContext
,它将从
DataGridTemplateColumn
中提取必要的项目。代码如下:

DataRowView


<Window x:Class="DataGridTemplateColumnSample.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:dg="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit" Title="Window1" Height="300" Width="300"> <Window.Resources> <ResourceDictionary> <DataTemplate x:Key="MyDataTemplate" DataType="DataRowView"> <StackPanel Orientation="Horizontal"> <Button Background="Green" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="5,0,0,0" Content="{Binding Path=nameData}"></Button> <TextBlock Background="Green" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,0,0" Text="{Binding Path=nameData}"></TextBlock> </StackPanel> </DataTemplate> </ResourceDictionary> </Window.Resources> <Grid> <dg:DataGrid Grid.Row="1" AutoGenerateColumns="True" x:Name="dataGrid1" SelectionMode="Single" CanUserAddRows="False" CanUserSortColumns="true" CanUserDeleteRows="False" AlternatingRowBackground="AliceBlue" AutoGeneratingColumn="dataGrid1_AutoGeneratingColumn" ItemsSource="{Binding}" VirtualizingStackPanel.VirtualizationMode="Standard" /> </Grid> </Window>
注意:此方法似乎仅适用于容器虚拟化关闭或标准模式。如果 

VirtualizationMode 设置为回收,则不会应用模板。


8
投票

http://social.msdn.microsoft.com/Forums/en/wpf/thread/8b2e94b7-3c44-4642-8acc-851de5285062

代码:

using System.Data; using System.Windows; using Microsoft.Windows.Controls; namespace DataGridTemplateColumnSample { public partial class Window1 { public Window1() { InitializeComponent(); DataContext = GetDummyData().DefaultView; } private static DataTable GetDummyData() { var dt = new DataTable("Foo"); dt.Columns.Add(new DataColumn("OneColumn", typeof(MyData))); dt.Columns.Add(new DataColumn("AnotherColumn", typeof(MyData))); dt.Rows.Add(new MyData("Row1C1", true), new MyData("Row1C2", true)); dt.Rows.Add(new MyData("Row2C1", false), new MyData("Row2C2", true)); dt.AcceptChanges(); return dt; } private void dataGrid1_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e) { var column = new DataRowColumn(e.PropertyName); column.Header = e.Column.Header; column.CellTemplate = (DataTemplate)Resources["MyDataTemplate"]; e.Column = column; } } public class DataRowColumn : DataGridTemplateColumn { public DataRowColumn(string column) { ColumnName = column; } public string ColumnName { get; private set; } protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem) { var row = (DataRowView) dataItem; var item = row[ColumnName]; cell.DataContext = item; var element = base.GenerateElement(cell, item); return element; } } public class MyData { public MyData(string name, bool data) { nameData = name; showData = data; } public string nameData { get; set; } public bool showData { get; set; } } }



0
投票

private void dataGrid1_AutoGeneratingColumn(object sender, Microsoft.Windows.Controls.DataGridAutoGeneratingColumnEventArgs e) { if (e.PropertyType == typeof(MyData)) { MyDataGridTemplateColumn col = new MyDataGridTemplateColumn(); col.ColumnName = e.PropertyName; // so it knows from which column to get MyData col.CellTemplate = (DataTemplate)FindResource("MyDataTemplate"); e.Column = col; e.Column.Header = e.PropertyName; } } public class MyDataGridTemplateColumn : DataGridTemplateColumn { public string ColumnName { get; set; } protected override System.Windows.FrameworkElement GenerateElement(DataGridCell cell, object dataItem) { // The DataGridTemplateColumn uses ContentPresenter with your DataTemplate. ContentPresenter cp = (ContentPresenter)base.GenerateElement(cell, dataItem); // Reset the Binding to the specific column. The default binding is to the DataRowView. BindingOperations.SetBinding(cp, ContentPresenter.ContentProperty, new Binding(this.ColumnName)); return cp; } }

© www.soinside.com 2019 - 2024. All rights reserved.