简体   繁体   English

用动态列填充数据网格

[英]Filling a Datagrid with dynamic Columns

I have an Datagrid which needs to get filled dynamicly.我有一个需要动态填充的 Datagrid。

The tablelayout is like:表布局是这样的:

id | image | name | Description | Name-1 | Name-N

The first 4 columns are static the others are dynamic.前 4 列是静态的,其他是动态的。 The User should be able to add as many users as he wants.用户应该能够根据需要添加任意数量的用户。

I try to compare data of multiple users by putting them next to each other in the table.我尝试通过将多个用户的数据放在表中来比较它们。

Right now I have an Listbox whitch containes the Names of the dynamic generated Columns and an method that filles the static columns.现在我有一个列表框,其中包含动态生成的列的名称和填充静态列的方法。 I also can load the datas for each User.我还可以为每个用户加载数据。 now I need to merge them to one big Table.现在我需要将它们合并到一张大表中。

The main Problem is now: How to put the "Userdata" and the static content in one datagrid.现在的主要问题是:如何将“用户数据”和静态内容放在一个数据网格中。

There are at least three ways of doing this:至少有三种方法可以做到这一点:

  1. Modify the DataGrid's columns manually from code-behind从代码隐藏手动修改 DataGrid 的列
  2. Use a DataTable as the ItemsSource *使用 DataTable 作为 ItemsSource *
  3. Use a CustomTypeDescriptor使用自定义类型描述符

    *recommended for simplicity *为简单起见推荐


1st approach: use code-behind to generate the DataGrid's columns at runtime.第一种方法:使用代码隐藏在运行时生成 DataGrid 的列。 This is simple to implement, but maybe feels a bit hackish, especially if you're using MVVM.这很容易实现,但可能感觉有点hackish,尤其是在您使用MVVM 时。 So you'd have your DataGrid with fixed columns:所以你的 DataGrid 有固定的列:

<DataGrid x:Name="grid">
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding id}" Header="id" />
        <DataGridTextColumn Binding="{Binding image}" Header="image" />
    </DataGrid.Columns>
</DataGrid>

When you have your "Names" ready, then modify the grid by adding/removing columns, eg:当您准备好“名称”后,然后通过添加/删除列来修改网格,例如:

// add new columns to the data grid
void AddColumns(string[] newColumnNames)
{
    foreach (string name in newColumnNames)
    {
        grid.Columns.Add(new DataGridTextColumn { 
            // bind to a dictionary property
            Binding = new Binding("Custom[" + name + "]"), 
            Header = name 
        });
    }
}

You'll want to create a wrapper class, which should contain the original class, plus a dictionary to contain the custom properties.您需要创建一个包装类,它应该包含原始类,以及一个包含自定义属性的字典。 Let's say your main row class is "User", then you'd want a wrapper class something like this:假设您的主行类是“用户”,那么您需要一个类似这样的包装类:

public class CustomUser : User
{
    public Dictionary<string, object> Custom { get; set; }

    public CustomUser() : base()
    {
        Custom = new Dictionary<string, object>();
    }
}

Populate the ItemsSource with a collection of this new "CustomUser" class:使用这个新的“CustomUser”类的集合填充ItemsSource

void PopulateRows(User[] users, Dictionary<string, object>[] customProps)
{
    var customUsers = users.Select((user, index) => new CustomUser {
        Custom = customProps[index];
    });
    grid.ItemsSource = customUsers;
}

So tying it together, for example:所以把它绑在一起,例如:

var newColumnNames = new string[] { "Name1", "Name2" };
var users = new User[] { new User { id="First User" } };
var newProps = new Dictionary<string, object>[] {
    new Dictionary<string, object> { 
        "Name1", "First Name of First User",
        "Name2", "Second Name of First User",
    },
};
AddColumns(newColumnNames);
PopulateRows(users, newProps);

2nd approach: use a DataTable .第二种方法:使用DataTable This makes use of the custom-type infrastructure under the hood, but is easier to use.这在引擎盖下使用了自定义类型的基础设施,但更易于使用。 Just bind the DataGrid's ItemsSource to a DataTable.DefaultView property:只需将 DataGrid 的ItemsSource绑定到DataTable.DefaultView属性:

<DataGrid ItemsSource="{Binding Data.DefaultView}" AutoGenerateColumns="True" />

Then you can define the columns however you like, eg:然后你可以定义你喜欢的列,例如:

Data = new DataTable();

// create "fixed" columns
Data.Columns.Add("id");
Data.Columns.Add("image");

// create custom columns
Data.Columns.Add("Name1");
Data.Columns.Add("Name2");

// add one row as an object array
Data.Rows.Add(new object[] { 123, "image.png", "Foo", "Bar" });

3rd approach: make use of the extensibility of .Net's type system.第三种方法:利用.Net 类型系统的可扩展性。 Specifically, use a CustomTypeDescriptor .具体来说,使用CustomTypeDescriptor This allows you to create a custom type at runtime;这允许您在运行时创建自定义类型; which in turn enables you to tell the DataGrid that your type has the properties "Name1", "Name2", ... "NameN", or whatever others you want.这反过来又使您能够告诉 DataGrid 您的类型具有属性“Name1”、“Name2”、...“NameN”或您想要的任何其他属性。 See here for a simple example of this approach.有关方法的简单示例,请参见此处

2nd approach : use a DataTable.第二种方法:使用数据表。 This makes use of the custom-type infrastructure under the hood, but is easier to use.这在引擎盖下使用了自定义类型的基础设施,但更易于使用。 Just bind the DataGrid's ItemsSource to a DataTable.DefaultView property:只需将 DataGrid 的 ItemsSource 绑定到 DataTable.DefaultView 属性:

This almost worked but instead of binding to the DataTable.DefaultView property property I created a property of type DataView and bound to that.这几乎有效,但我没有绑定到 DataTable.DefaultView 属性属性,而是创建了一个 DataView 类型的属性并绑定到该属性。

<DataGrid ItemsSource="{Binding DataView, Mode=TwoWay}" AutoGenerateColumns="True" />

This allows the binding to be two way, binding to the DataTable.DefaultView cannot be a TwoWay binding.这允许绑定是双向的,绑定到 DataTable.DefaultView 不能是双向绑定。 In the View Model在视图模型中

    public DataView DataView
    {
        get { return _dataView; }
        set
        {
            _dataView = value;
            OnPropertyChanged("DataView");
        }
    }

With this setup I could not only define the columns dynamically when the View Model is initialized, but could update and change the data table dynamically at any time.通过这种设置,我不仅可以在初始化视图模型时动态定义列,还可以随时动态更新和更改数据表。 In using the approach as defined by McGarnagle above, the view schema was not refreshing when the DataTable was updated with a new data source.在使用上述 McGarnagle 定义的方法时,当使用新数据源更新 DataTable 时,视图模式不会刷新。

I'm currently using another approach.我目前正在使用另一种方法。 I am not sure if it is right to do it like this, but it works.我不确定这样做是否正确,但它确实有效。 I made a small sample.我做了一个小样本。

Keep in mind that for this to work, every entry in the Datagrid needs to have the same dynamic columns, making it a bit less flexible.请记住,要使其正常工作,Datagrid 中的每个条目都需要具有相同的动态列,因此灵活性稍差。 But if you have entries with different amounts of columns in each entry, then a Datagrid is probably the wrong Approach anyways.但是,如果每个条目中有不同数量的条目,那么无论如何 Datagrid 可能是错误的方法。

These are my classes:这些是我的课程:

 public class Person
    {
        public ObservableCollection<Activity> Hobbys { get; set; }
        public string Name { get; set; }
    }
 public class Activity
    {
        public string Name { get; set; }
    }

And this is the Code Behind:这是背后的代码:

public MainWindow()
        {
            InitializeComponent();
            DataContext = this;

            ObservableCollection<Activity> hobbys = new ObservableCollection<Activity>();
            hobbys.Add(new Activity() { Name = "Soccer" });
            hobbys.Add(new Activity() { Name = "Basketball" });

            Community = new ObservableCollection<Person>();
            Community.Add(new Person() { Name = "James", Hobbys = hobbys });
            Community.Add(new Person() { Name = "Carl", Hobbys = hobbys });
            Community.Add(new Person() { Name = "Homer", Hobbys = hobbys });

            MyGrid.Columns.Add(new DataGridTextColumn() { Header = "Name", Binding = new Binding("Name") });    //Static Column
            int x = 0;
            foreach (Activity act in Community[0].Hobbys)  //Create the dynamic columns
            {
                MyGrid.Columns.Add(new DataGridTextColumn() { Header = "Activity", Binding = new Binding("Hobbys["+x+"].Name") });
                x++;
            }

        }

And in the .XAML is simply:而在 .XAML 中只是:

  <DataGrid Name="MyGrid" ItemsSource="{Binding Community}" AutoGenerateColumns="False"/>

如果您不需要将其显示到单个大 DataGrid(table) 中,那么您可以拥有一个带有id、image、name、DescriptionDataGrid 并且当在该 DataGrid 上选择了其中一条记录时,您可以使用以下内容显示/刷新 ListBox与所选记录相关的图像名称

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM