使用 TemplateColumns 将 WPF DataGrid 绑定到 DataTable [英] Binding WPF DataGrid to DataTable using TemplateColumns

查看:32
本文介绍了使用 TemplateColumns 将 WPF DataGrid 绑定到 DataTable的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have tried everything and got nowhere so I'm hoping someone can give me the aha moment. I simply cannot get the binding to pull the data in the datagrid successfully.

我有一个包含多列 MyDataType 的数据表

I have a DataTable that contains multiple columns with of MyDataType

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

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

MyDataType has 2 properties (A string, a boolean) I have created a test DataTable

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,我想用它来显示我的 DataTable.但我想要做的就是更改每个单元格的呈现方式,以显示每个单元格的 [TextBlock][Button] 值绑定到 MyData 对象,而这正是我遇到很多麻烦的地方.

I have a WPF DataGrid which I want to show my DataTable. But all I want to do is to change how each cell is rendered to show [TextBlock][Button] per cell with values bound to the MyData object and this is where I'm having a tonne of trouble.

我的 XAML 看起来像这样

My XAML looks like this

<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

Now all I do once loaded is to attempt to bind the DataTable to the WPF DataGrid

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

TextBlock 和 Button 显示出来,但它们没有绑定,这使它们留空.任何人都可以让我知道他们是否知道如何解决这个问题.这应该很简单,这就是微软让我们相信的.我在 AutoGenerating 事件期间设置了 Column.CellTemplate 并且仍然没有绑定.

The TextBlock and Button show up, but they don't bind, which leaves them blank. Could anyone let me know if they have any idea how to fix this. This should be simple, thats what Microsoft leads us to believe. I have set the Column.CellTemplate during the AutoGenerating event and still get no binding.

请帮忙!!!

推荐答案

更新以反映 Aran Mulholland 的输入(见评论)

显然 DataGrid 将整个 DataRowView 传递给每个单元格.这就是绑定不起作用的原因.您的 DataTemplate 期望 DataContext 的类型为 MyData,但它的类型为 DataRowView.我建议的(有点hack-ish)解决方法是创建一个自定义的 DataGridTemplateColumn 来获取你想要的 DataContext,它将从 DataRowView 中提取必要的项目>.代码如下:

Apparently the DataGrid is passing the entire DataRowView to each cell. That's why the binding doesn't work. Your DataTemplate expects the DataContext to be of type MyData, but instead it is of type DataRowView. My proposed (somewhat hack-ish) workaround to get the DataContext you want is to create a custom DataGridTemplateColumn that will extract the necessary item from the DataRowView. The code is below:

<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>

<小时>

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; }
    }
}

注意:此方法似乎仅适用于关闭或处于标准模式的容器虚拟化.如果 VirtualizationMode 设置为回收模板未应用.

Note: This approach only appears to work with container virtualization off or in Standard mode. If the VirtualizationMode is set to Recycling the template is not applied.

这篇关于使用 TemplateColumns 将 WPF DataGrid 绑定到 DataTable的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆