Programmatically add columns to datagrid not compi

2019-09-02 19:27发布

问题:

This is the continuation to

OnEvent datagrid column add fail

I have seen this post:

How to add Data to a WPF datagrid programatically

the datagrid is simply this:

<DataGrid Name="dtgResults" Background="Transparent" AutoGenerateColumns="False"/>

in which everything seems to work fine but when I put it in my solution it doesn't compile:

Can anyone explain me why?

---EDIT---

I realize now that I have misunderstood what's in the link above. In short I have a datagrid binded to an observable collection. I have to add two more columns. How can that be done?

---EDIT2---- for CBreeze

 dtgResults.ItemsSource = obcmMyDim;<--------previous data here
 DataGridTextColumn textColumn1 = new DataGridTextColumn();
 textColumn1.Header = "AAA1";
 textColumn1.Binding = new Binding("AAA1");

 DataGridTextColumn textColumn2 = new DataGridTextColumn();
 textColumn2.Header = "AAA2";
 textColumn2.Binding = new Binding("AAA2");

 Application.Current.Dispatcher.BeginInvoke(new ThreadStart(() => dtgResults.Columns.Add(textColumn1)));
 Application.Current.Dispatcher.BeginInvoke(new ThreadStart(() => dtgResults.Columns.Add(textColumn2)));

 dtgResults.Items.Add(new { AAA1 = "Col1Row1", AAA2 = "Col2Row1"});
 dtgResults.Items.Add(new { AAA1 = "Col1Row2", AAA2 = "Col2Row2" });

---EDIT 3--- for JH So in short I have that observable collection which binded to the datagrid make the following output:

then I add the columns with your method:

var names = obcmMyDim.First().obcItemsName; // All entries must have the same list of obcItemsName and in the same order
    for (int i = 0; i < names.Count; i++)
    {
      DataGridTextColumn c = new DataGridTextColumn();
      c.Header = names[i];

      var b = new Binding();
      string str = string.Format("obcmMyDim.obcItemsMeasured[{0}]", i);
      b.Path = new PropertyPath(str);
      b.Mode = BindingMode.TwoWay;

      c.Binding = b;

      dtgResults.Columns.Add(c);
    }

as for the binded array

and the bind str is "obcmMyDim.obcItemsMeasured[0]" ...1....n

but what I get is that the columns are there but they are empty

回答1:

Have you tried something like;

dtgResults.Columns.Add(new DataGridTextColumn { Header = "a.1"});
dtgResults.Columns.Add(new DataGridTextColumn { Header = "a.2"});

EDIT:

 for (int i = 1; i <= 10; i++)
 {
     dtgResults.Items.Add(new { a.1 = "Test" + i, a.2 = "Test" + i});
 }


回答2:

It does not compiling because you use ItemCollection. I think you did not create your own class like in answer from link and used System.Windows.Controls.ItemCollection, which can`t used in this case.



回答3:

You can bind to an item in an array but you'll have to make sure that all the arrays are the same (same fields, in the same order so that the index into them is consistent). Here is an example of it based on the other question you had.

Note that the field obcItemsMeasured had to be changed into a property since bindings require properties (not fields).

XAML:

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication2"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <DataGrid x:Name="dtgResults" CanUserAddRows="False" AutoGenerateColumns="False">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding NameAxisDimension}" Header="NameAxisDimension" />
            <DataGridTextColumn Binding="{Binding Nominal}" Header="Nominal" />
            <DataGridTextColumn Binding="{Binding UpperTolerance}" Header="UpperTolerance" />
            <DataGridTextColumn Binding="{Binding LowerTolerance}" Header="LowerTolerance" />
        </DataGrid.Columns>
    </DataGrid>
</Window>

Code:

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace WpfApplication2
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            // Build list of MyDimensions manually (since I don't have access to your data)
            var obcmMyDim = new ObservableCollection<MyDimension>(CreateData());
            dtgResults.ItemsSource = obcmMyDim;

            var names = obcmMyDim.First().obcItemsName; // All entries must have the same list of obcItemsName and in the same order
            for (int i=0; i<names.Count; i++)
            {
                DataGridTextColumn c = new DataGridTextColumn();
                c.Header = names[i];

                var b = new Binding();
                b.Path = new PropertyPath(string.Format("obcItemsMeasured[{0}]", i)); // Binding is based on index into array, thats why all entries have to have the same dynamic fields
                b.Mode = BindingMode.TwoWay;

                c.Binding = b;

                dtgResults.Columns.Add(c);
            }

        }
        public IList<MyDimension> CreateData()
        {
            List<MyDimension> Dimensions = new List<MyDimension>();
            string[] names = new string[] { "PART11", "PART20" }; // They must all have the same obcItemsName/obcItemsMeasured entries, and in the same order
            Dimensions.Add(CreateItem("LOC1-X", names, 0, 0));
            Dimensions.Add(CreateItem("LOC1-Y", names, 0, 0));
            Dimensions.Add(CreateItem("LOC1-D", names, 10.0, 10.1));
            Dimensions.Add(CreateItem("LOC1-RN", names, 0, 0));
            Dimensions.Add(CreateItem("LOC2-X", names, 0, 0));
            Dimensions.Add(CreateItem("LOC2-Y", names, 0, 0));
            Dimensions.Add(CreateItem("LOC1-DF", names, 10.2, 10.3));
            Dimensions.Add(CreateItem("LOC2-TP", names, 0, 0));
            Dimensions.Add(CreateItem("DIST1-M", names, 14.14214, 14.14215));
            Dimensions.Add(CreateItem("DIST2-M", names, 10.4, 10.5));
            // etc...
            return Dimensions;
        }
        public MyDimension CreateItem(string name, string[] names, params double[] values)
        {
            var d = new MyDimension();
            d.NameAxisDimension = name;
            for (int i = 0; i < names.Length; i++)
            {
                d.obcItemsName.Add(names[i]);
                d.obcItemsMeasured.Add(values[i]);
            }
            return d;
        }
    }
    public class MyDimension
    {
        public MyDimension()
        {
            obcItemsName = new ObservableCollection<string>();
            obcItemsMeasured = new ObservableCollection<double>();
        }
        public string NameAxisDimension { get; set; }
        public double Nominal { get; set; }
        public double UpperTolerance { get; set; }
        public double LowerTolerance { get; set; }
        public ObservableCollection<string> obcItemsName;
        public ObservableCollection<double> obcItemsMeasured { get; set; } // Has to be a property since it is used in the binding
    }
}

Screenshot: