1

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:

enter image description here

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:

enter image description here

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

enter image description here

enter image description here

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

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

enter image description here

Community
  • 1
  • 1
Patrick
  • 3,073
  • 2
  • 22
  • 60
  • 1
    What's the error message? – diiN__________ Feb 09 '16 at 14:55
  • I would recommend using DataBinding instead of adding items one by one. If you're coming from WinForms, you should rethink the way you link the controls to actual data. – Alex Feb 09 '16 at 14:59
  • I can't get to do that. I have already posted the question here http://stackoverflow.com/questions/35290099/how-to-databing-datagrid-with-class-with-collection-and-modify-columns-according – Patrick Feb 09 '16 at 15:01

3 Answers3

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});
 }
CBreeze
  • 2,925
  • 4
  • 38
  • 93
  • For the header it's fine but how to add the values of the column? – Patrick Feb 09 '16 at 15:18
  • @Patrick add a new item? `dtgResults.Items.Add(new { a.1 = "Test1", a.2 = "Test2" });` – CBreeze Feb 09 '16 at 15:22
  • The column is formed with a number of values according to the number of rows. So I am puzzled how can I add it as a single value??? I would expect something like a.1 = {"Col1Row1", "Col1Row2",.....} – Patrick Feb 09 '16 at 15:42
  • VERY WELL!!! We are getting nearer. The only problem is that it doesn't add columns, it deleted all the columns and then add only the new ones. – Patrick Feb 09 '16 at 15:55
  • @Patrick So programatically add the old ones in too? If you don't use `DataBinding` I assume this is what you have to do, hence why so many people suggest to use `DataBinding`. You just need to add the values into the loops, so `dtgResults.Items.Add(new { a.1 = "Test" + i, a.2 = "Test" + i, col3 = "Test" + i, col4 = "Test" +i etc etc});` – CBreeze Feb 09 '16 at 15:57
  • @Patrick there's no easy way round it - you're trying to do two different things the same way – CBreeze Feb 09 '16 at 16:01
  • No wait it's getting better by little steps. See the EDIT 3 pic. It's adding columns but they are empty. – Patrick Feb 09 '16 at 16:27
0

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.

galakt
  • 1,374
  • 13
  • 22
0

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:

enter image description here

J.H.
  • 4,232
  • 1
  • 18
  • 16
  • Thank you for your help. I am safe on the fact that all array have the same lenght. Your code produces the same problems that I noticed with CBreeze's solution. Please see my edit. – Patrick Feb 11 '16 at 11:04
  • Did you change obcItemsMeasured to a property? It won't work if it's just a member field. Has to be a property for bindings to work. – J.H. Feb 11 '16 at 12:35