简体   繁体   English

绑定列表<list<object> > 到代码隐藏中的 DataGrid 列</list<object>

[英]Binding List<List<object>> to DataGrid columns in code-behind

I have a problem binding List<List> to DataGrid columns in code-behind.我在将 List<List> 绑定到代码隐藏中的 DataGrid 列时遇到问题。 Here is my list of lists:这是我的清单:

private List<List<object>> matrix = new List<List<object>>()
     {
         new List<object>(){53, 2500, 3000, 3500, 4000, 4500, 5000},
         new List<object>(){2500, 1, 0, 0, 0, 0, 0},
         new List<object>(){3000, 0, 1, 0, 0, 0, 0},
         new List<object>(){3500, 0, 0, 1, 0, 0, 0},
         new List<object>(){4000, 0, 0, 0},
         new List<object>(){4500, 0, 0, 0, 0, 1, 0},
         new List<object>(){5000, 9, 7, 5, 4, 1, 1},
         new List<object>(){1, 0, 0, 0, 0, 0, 0},
         new List<object>(){2, 0, 0, 0, 0, 0, 0},
         new List<object>(){0, 0, 0, 0, 0, 0, 0}
     };

    public List<List<object>> Matrix
    {
        get { return matrix; }
        set
        {
            matrix = value;
            OnPropertyChanged(nameof(Matrix));
        }

I've done this in XAML like this:我在 XAML 中这样做是这样的:

<DataGrid ItemsSource="{Binding Matrix}" VerticalAlignment="Top" FontSize="14" x:Name="matrixDataGrid" Height="420" Width="630" MinRowHeight="20" AutoGenerateColumns="False" >
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Path=[0], Mode=TwoWay}"/>
            <DataGridTextColumn Binding="{Binding Path=[1], Mode=TwoWay}"/>
            <DataGridTextColumn Binding="{Binding Path=[2], Mode=TwoWay}"/>
            <DataGridTextColumn Binding="{Binding Path=[3], Mode=TwoWay}"/>
            <DataGridTextColumn Binding="{Binding Path=[4], Mode=TwoWay}"/>
            <DataGridTextColumn Binding="{Binding Path=[5], Mode=TwoWay}"/>
            <DataGridTextColumn Binding="{Binding Path=[6], Mode=TwoWay}"/>
            <DataGridTextColumn Binding="{Binding Path=[7], Mode=TwoWay}"/>
            <DataGridTextColumn Binding="{Binding Path=[8], Mode=TwoWay}"/>
            <DataGridTextColumn Binding="{Binding Path=[9], Mode=TwoWay}"/>
        </DataGrid.Columns>
    </DataGrid>

And here is the result: the result of XAML binding这是结果: XAML 绑定的结果

And I would call it half-working.我会称之为半工作。 The first problem is an extra row and 3 extra columns.第一个问题是一个额外的行和 3 个额外的列。 The second one is that I will have a lot of work if I would like to have 1000 columns.第二个是如果我想要 1000 列,我将有很多工作要做。 Also, there are a lot of XAML binding errors: Binding errors .还有很多 XAML binding errors: Binding errors And I don't even know how this specific binding works, and it looks strange.而且我什至不知道这个特定的绑定是如何工作的,看起来很奇怪。 I would be glad for the explanation.我会很高兴的解释。

My unsuccessful attempts to do this in code-behind look like this:我在代码隐藏中尝试执行此操作的失败尝试如下所示:

Binding binding = new Binding();
binding.Source = Matrix; 
binding.Path = new PropertyPath("[0]"); 
binding.Mode = BindingMode.TwoWay;
columnOne.Binding = binding;

XAML file at the moment: XAML 目前档案:

<DataGrid ItemsSource="{Binding Matrix}" VerticalAlignment="Top" FontSize="14" x:Name="matrixDataGrid" Height="420" Width="630" MinRowHeight="20" AutoGenerateColumns="False" >
        <DataGrid.Columns>
            <DataGridTextColumn Width="50" x:Name="columnOne" />
        </DataGrid.Columns>
    </DataGrid>

I only get empty column: result of attempt .我只得到空列: result of attempt I've seen someone doing this with DataTable, but I would like to do this the way I want if it is possible.我见过有人用 DataTable 这样做,但如果可能的话,我想按照我想要的方式来做。

I wouldn't mess with a DataGrid , it's just too much hassle unless you need specific features of the DataGrid like sortable headers, grouping, etc. DataGrid also will not handle a huge matrix very well, since each cell is pretty heavy UI wise.我不会弄乱DataGrid ,这太麻烦了,除非您需要DataGrid的特定功能,如可排序的标题、分组等DataGrid也不能很好地处理巨大的矩阵,因为每个单元格在 UI 方面都非常笨重。

Instead, Since you have a List of List s, you can do the same thing with an ItemsControl of ItemsControl s.相反,由于您有一个ListList ,您可以使用ItemsControlItemsControl做同样的事情。 As long as each element has the same height/width, then it would come out looking just like the DataGrid .只要每个元素具有相同的高度/宽度,那么它看起来就像DataGrid一样。 You could do that by fixing the size of each element, or set the ItemsPanel to something that enforces consistent sizing (like UniformGrid ).您可以通过固定每个元素的大小来做到这一点,或者将ItemsPanel设置为强制大小一致的东西(如UniformGrid )。

To make binding work so the cells are editable, you need to wrap the value in each matrix cell in something that implements INotifyPropertyChanged.要使绑定起作用以便单元格可编辑,您需要将每个矩阵单元格中的值包装在实现 INotifyPropertyChanged 的内容中。

public class ItemViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler? PropertyChanged;
    private void OnPropertyChanged([CallerMemberName] string p = null) 
        => PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(p));
      
    private int _value;
    public int Value
    {
        get => _value;
        set
        {
           _value = value;
           OnPropertyChanged();
        }
    }

    public static implicit operator int(Item i) => i.Value;
    public static implicit operator Item(int i) => new () { Value = i};

    public static int[] GetArray(IEnumerable<Item> input) 
        => input.Select(i => i.Value).ToArray();

    public static int[][] GetMatrix(IEnumerable<IEnumerable<Item>> input) 
        => input.Select(ToArray).ToArray();
}

Here's the XAML for a MatrixGrid, derived from ItemsControl.这是从 ItemsControl 派生的 MatrixGrid 的 XAML。 The code behind doesn't have anything in it but the autogenerated constructor.除了自动生成的构造函数之外,后面的代码没有任何内容。

<ItemsControl x:Class="WpfApp1.MatrixGrid" x:Name="ic"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              ItemsSource="{Binding}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ItemsControl ItemsSource="{Binding}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <UniformGrid Columns="{Binding ElementName=ic, Path=ItemsSource.Count}"/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <TextBox Text="{Binding Value, UpdateSourceTrigger=PropertyChanged}"
                                 TextAlignment="Center"/>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Demo:演示:

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApp1">
    <local:MatrixGrid x:Name="matrixGrid"/>
</Window>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        matrixGrid.ItemsSource = Matrix;
    }

    public List<List<ItemViewModel>> Matrix { get; } = new List<List<Item>>()
    {
        new (){53, 2500, 3000, 3500, 4000, 4500, 5000},
        new (){2500, 1, 0, 0, 0, 0, 0},
        new (){3000, 0, 1, 0, 0, 0, 0},
        new (){3500, 0, 0, 1, 0, 0, 0},
        new (){4000, 0, 0, 0},
        new (){4500, 0, 0, 0, 0, 1, 0},
        new (){5000, 9, 7, 5, 4, 1, 1},
        new (){1, 0, 0, 0, 0, 0, 0},
        new (){2, 0, 0, 0, 0, 0, 0},
        new (){0, 0, 0, 0, 0, 0, 0}
    };
}

在此处输入图像描述

Nice thing about this is that there's no need for code behind or generating bindings programmatically.这样做的好处是不需要隐藏代码或以编程方式生成绑定。

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

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