WPF DataGrid 与 ObservableCollection 绑定

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27184904/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 12:44:47  来源:igfitidea点击:

WPF DataGrid binding with ObservableCollection

wpfxamlmvvmdatagridobservablecollection

提问by Rosi

I'm trying to bind a ObservableCollection with rows of data to my datagrid. I'm aiming on making the datagrid update itself (if data is added), it didn't worked when using a DataTable. I tested this approach and it works just fine, my datagrid ist bound to ResultTable property and the property names are the column names.

我正在尝试将带有数据行的 ObservableCollection 绑定到我的数据网格。我的目标是让 datagrid 自行更新(如果添加了数据),它在使用 DataTable 时不起作用。我测试了这种方法并且它工作得很好,我的数据网格绑定到 ResultTable 属性并且属性名称是列名称。

public class MainWindowViewModel
{
    public MainWindowViewModel()
    {
        ResultTable = new ObservableCollection<Row>();
        ResultTable.Add(new Row() { Name = "Peter", Age = "21", Sex = "Male" });
        ResultTable.Add(new Row() { Name = "Sara", Age = "25", Sex = "Female" });
        ResultTable.Add(new Row() { Name = "Mike", Age = "28", Sex = "Male" });
    }

    public ObservableCollection<Row> ResultTable { get; set; }
}

public class Row
{
    public string Name { get; set; }
    public string Age { get; set; }
    public string Sex { get; set; }
}

Now my question is, how can I do this dynamically? This was my second approach and looks like nothing in the DataGrid...

现在我的问题是,我怎样才能动态地做到这一点?这是我的第二种方法,在 DataGrid 中看起来什么都没有......

public class MainWindowViewModel
{
    public MainWindowViewModel()
    {
        ResultTable = new ObservableCollection<Row>();
        var row = new Row();
        row.Columns.Add(new Item() { Name = "Name", Value = "Peter" });
        row.Columns.Add(new Item() { Name = "Age", Value = "21" });
        row.Columns.Add(new Item() { Name = "Sex", Value = "Male" });
        ResultTable.Add(row);
    }

    public ObservableCollection<Row> ResultTable { get; set; }
}

public class Row
{
    public List<Item> Columns = new List<Item>();
}

public class Item
{
    public string Name { get; set; }
    public string Value { get; set; }
}

But now the question is, how can I say the DataGrid that each Name property in columns List is the column header. And each Value is the value of the row?

但现在的问题是,我怎么能说 DataGrid 列 List 中的每个 Name 属性都是列标题。每个值是行的值?

This is my xaml (nothing fancy):

这是我的 xaml(没什么特别的):

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:MainWindowViewModel x:Name="MainWindowViewModel" />
    </Window.DataContext>
    <Grid>
        <DataGrid ItemsSource="{Binding ResultTable}"
                  AutoGenerateColumns="True" />
    </Grid>
</Window>

回答by SWilko

Ok so have tested this and works as per your diagram in the comments below.

好的,所以已经测试了这个并按照你在下面评论中的图表工作。

Row class

行类

public class Row
{
    private ObservableCollection<Item> columns = new ObservableCollection<Item>();

    public Row(params Item[] items)
    {
        foreach (var item in items)
            Columns.Add(item);
    }

    public ObservableCollection<Item> Columns
    {
        get { return columns; }
        set { columns = value; }
    }
}

Item.cs

项目.cs

public class Item 
{
    public Item(string name, string value)
    {
        this.Name = name;
        this.Value = value;
    }
    public string Name { get; set; }
    public string Value { get; set; }     
}

Custom DataGRidBoundColumn

自定义 DataGRidBoundColumn

public class CustomBoundColumn : DataGridBoundColumn
{
    public string TemplateName { get; set; }

    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
    {
        var binding = new Binding(((Binding)Binding).Path.Path);
        binding.Source = dataItem;

        var content = new ContentControl();
        content.ContentTemplate = (DataTemplate)cell.FindResource(TemplateName);
        content.SetBinding(ContentControl.ContentProperty, binding);
        return content;
    }

    protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
    {
        return GenerateElement(cell, dataItem);
    }
}

MainWindow.xaml.cs

主窗口.xaml.cs

public partial class MainWindow : Window
{
    public ObservableCollection<Row> ResultTable
    {
        get;
        set;
    }
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;
        Loaded += (s, args) =>
            {
                this.ResultTable = new ObservableCollection<Row>();
                ResultTable.Add(new Row(new Item("Name", "Peter"), new Item("Age", "21"), new Item("Sex", "Male")));
                ResultTable.Add(new Row(new Item("Name", "Sara"), new Item("Age", "25"), new Item("Sex", "Female")));
                ResultTable.Add(new Row(new Item("Name", "Mike"), new Item("Age", "28"), new Item("Sex", "Male")));

                var columns = ResultTable.First()
                           .Columns
                           .Select((x, i) => new { Name = x.Name, Value = x.Value, Index = i })
                           .ToArray();

                foreach (var column in columns)
                {
                    var binding = new Binding(string.Format("Columns[{0}].Value", column.Index));
                    data.Columns.Add(new CustomBoundColumn()
                        {
                            Header = column.Name,
                            Binding = binding,
                            TemplateName = "CustomTemplate"
                        });                        
                }
                data.ItemsSource = this.ResultTable;

            };
    }
}

and finally the xaml nice and simple

最后是漂亮而简单的 xaml

 <Window.Resources>
    <DataTemplate x:Key="CustomTemplate">
        <Border Padding="3">
            <TextBlock Text="{Binding}" Foreground="Black" />
        </Border>
    </DataTemplate>
</Window.Resources>

    <Grid>
        <DataGrid Name="data"
                  AutoGenerateColumns="False">            
        </DataGrid>
    </Grid>     

This is done in code behind but I imagine you can adjust for your viewmodel. More about the fix can be found Here

这是在后面的代码中完成的,但我想您可以针对您的视图模型进行调整。可以在此处找到有关此修复程序的更多信息