【问题标题】:How to bind custom datagrid columns如何绑定自定义数据网格列
【发布时间】:2017-02-11 12:41:01
【问题描述】:

我需要修改数据网格,使每个列标题都有一个文本框、组合框和复选框,并且所有这些都必须绑定到一个属性。我花了很多时间尝试使用默认的 DataGrid 来实现这一点,但我认为这是不可能的,所以我决定创建一个自定义 DataGrid。

到目前为止,我有一个存储DataTable 的可绑定属性BindableColumns,所以我有了需要显示的数据。问题是我不知道如何将该数据传递给OnAutoGeneratedColumns,所以我可以将列添加到DataGrid 的Columns 属性。

public class BindableGrid : DataGrid
{
    public DataTable BindableColumns
    {
        get { return (DataTable)GetValue(BindableColumnsProperty); }
        set { SetValue(BindableColumnsProperty, value); }
    }

    public static readonly DependencyProperty BindableColumnsProperty =
        DependencyProperty.Register("BindableColumns", typeof(DataTable), typeof(BindableGrid), new PropertyMetadata(null, BindableColumnsPropertyChanged));

    private static void BindableColumnsPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
    {
        // This is where I get DataTable after binding
    }


    protected override void OnAutoGeneratedColumns(EventArgs e)
    {
        // This is where I need the DataTable to generate columns.
        // I don't know how to invoke this method myself.
        Columns.Add(new DataGridTemplateColumn
        {
            Header = "Test1",
            HeaderTemplate = new DataTemplate()
        });
    }
}

还有xaml:

<controls:BindableGrid ItemsSource="{Binding Data}" BindableColumns="{Binding Data}" AutoGenerateColumns="True">
 </controls:BindableGrid>

编辑:

感谢@Ramin,我有工作专栏。我在动态添加行时遇到了一些麻烦,因为DataGrid 期望行作为一个类,其变量名称与列的绑定完全相同。对于任何有问题的人,我是这样解决的:

for (var rowIndex = 0; rowIndex < data.Rows.Count; rowIndex++)
{
   dynamic row = new ExpandoObject();

   for (var i = 0; i < data.Columns.Count; i++)
   // Create variables named after bindings, and assign values
        ((IDictionary<string, object>)row)[data.Columns[i].ColumnName.Replace(' ', '_')] = data.Rows[rowIndex].ItemArray[i];

    // Add row to DataGrid
    dg.Items.Add(row);
}

【问题讨论】:

    标签: c# wpf xaml datagrid dependency-properties


    【解决方案1】:

    关于问题的根源,这里是一个带有模板标题的 DataGrid,其中包含一个 TextBox、ComboBox 和一个 CheckBox:

     <DataGrid >
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding}" >
                    <DataGridTextColumn.HeaderTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <TextBox Text="{Binding DataContext.Name, RelativeSource={RelativeSource AncestorType=DataGrid}}" />
                                <CheckBox IsChecked="{Binding DataContext.Value , RelativeSource={RelativeSource AncestorType=DataGrid}}"/>
                                <ComboBox ItemsSource="{Binding DataContext.Names , RelativeSource={RelativeSource AncestorType=DataGrid}}" SelectedIndex="0"/>
                            </StackPanel>
                        </DataTemplate>
                    </DataGridTextColumn.HeaderTemplate>
                </DataGridTextColumn>
            </DataGrid.Columns>
        </DataGrid>
    

    DataContext 正在使用自定义类:

    public MainWindow()
    {
        InitializeComponent();
        DataContext = new MyClass() { Name = "Name0", Value = true, Names = new string[2] { "Name1", "Name2" } };
    }
    
    public class MyClass
    {
        public string Name { get; set; }
        public bool Value { get; set; }
        public string[] Names { get; set; }
    }
    

    编辑

    您可以动态添加列:

        public void addNewColumn(Header h, string bindcol)
        {
            DataGridColumn col = new DataGridTextColumn(){Binding=new Binding(bindcol)};
            col.Header = h;
            col.HeaderTemplate = (DataTemplate)FindResource("dgh") as DataTemplate;
            dg.Columns.Add(col);
        }
    

    在 App.xaml 中:

    <Application.Resources>
        <DataTemplate x:Key="dgh">
            <StackPanel Orientation="Horizontal">
                <TextBox Text="{Binding Name}" />
                <CheckBox IsChecked="{Binding Value}"/>
                <ComboBox ItemsSource="{Binding Names}" SelectedIndex="0"/>
            </StackPanel>
        </DataTemplate>
    </Application.Resources>
    

    测试(假设有一个名为dg的DataGrid):

        public MainWindow()
        {
            InitializeComponent();
            var h1 = new Header()
            {
                Name = "Name0",
                Value = true,
                Names = new string[2] { "Name1", "Name2" }
            };
            var h2 = new Header()
            {
                Name = "Name1",
                Value = true,
                Names = new string[2] { "Name12", "Name22" }
            };
    
            addNewColumn(h1, "col1");
            addNewColumn(h2, "col2");
    
        }
    
        public class Header
        {
             public string Name { get; set; }
             public bool Value { get; set; }
             public string[] Names { get; set; }
        }
    

    请注意,“col1”和“col2”指的是数据网格的 ItemsSource。

    【讨论】:

    • 这对列数组有效吗?因为我不知道我的DataTable 中有多少列。我让用户加载转换为DataTable 的 csv 文件,因此每个文件的列数不同。
    • 我几乎可以使用它,但由于绑定,我无法动态添加行。 dg.Items.Add(); 需要一个具有与绑定相同的属性的对象,但在 C# 中我不能动态创建类。
    • 我想通了。我不得不使用ExpandoObject。谢谢,你真的让我免于花费数小时慢慢构建自定义控件。
    猜你喜欢
    • 2013-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-21
    • 2015-08-23
    • 1970-01-01
    • 1970-01-01
    • 2011-08-06
    相关资源
    最近更新 更多