Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding data to a specific column in a DataGrid

Tags:

c#

wpf

datagrid

I want to create a new column and then add values to only that new column on a button click event. Is that possible? The column might have a few rows underneath it, depending the amount of items in a quote.

What I have achieved so far:

My class where all my information is stored in

public class ViewQuoteItemList
{
    ...
    public double SupplierCost { get; set; }
    ...
}

I can create my column and bind it to my ViewQuoteItemList class

DataGridTextColumn columnFeedbackSupplier = new DataGridTextColumn();
columnFeedbackSupplier.Binding = new Binding("SupplierCost");
//The header of the column gets it's value from a combobox where you select a company to be added to the datagrid
columnFeedbackSupplier.Header = (cmbFeedbackSelectSupplier.SelectedItem as DisplayItems).Name;

From here I get my quote items from a different datagrid and I add them to my second datagrid where I want to add the new column and it's values

IList list = dgFeedbackAddCost.SelectedItems as IList;
IEnumerable<ViewQuoteItemList> items = list.Cast<ViewQuoteItemList>();

var collection = (from i in items
                  let a = new ViewQuoteItemList { SupplierCost = 0 }
                  select a).ToList();

Lastly, I add the new column to the second datagrid and set the collection as the datagrid's ItemSource

dgFeedbackSelectSupplier.Columns.Add(columnFeedbackSupplier);
dgFeedbackSelectSupplier.ItemsSource = collection;

My problem is that once I edit a cell of data from one of the suppliers, the whole row gets updated with that one value, because it's all bound to one class/item source. Can this be fixed?

EDIT:

"The whole row gets updated" means that every time I insert a value into one cell in a row, every single cell in that row gets updated with the same value. Here are some pictures showing what I mean. I want to edit all the data and this all happens on my second datagrid(dgFeedbackSupplier).

Here, I have two companies added with the 4 items that I want to compare prices with. Now I want to click on a single cell underneath a company and add a value for a certain item.

enter image description here

Here I double click on a cell to edit/change the value.enter image description here

Then when I change my value in the selected cell, every other company's value for that specific item in the same row gets updated with that same value. enter image description here

That's my problem and I need to have only that one cell's value changed, and not the whole row.

EDIT 2:

How can I convert this collection to ExpandoObject?

var collection = (from i in items
                  let a = new ViewQuoteItemList { Item = i.Item, Supplier = 25 }
                  select a).ToList();

EDIT 3:

My XAML:

<DataGrid x:Name="dgFeedbackSelectSupplier"  Margin="245,266,0,32" BorderBrush="#FFADADAD" ColumnWidth="*" AutoGenerateColumns="True" CanUserAddRows="False">
    <DataGrid.Columns>
        <DataGridTextColumn x:Name="columnFeedbackSupplierItem" IsReadOnly="True" Header="Item" Binding="{Binding Item}"/>
    </DataGrid.Columns>
</DataGrid>

And this is how my whole method looks like at the moment where I add my Columns and where I get the items from my other datagrid:

    private void btnFeedbackSelectSupplier_Click(object sender, RoutedEventArgs e)
    {
        supplier.Id = (cmbFeedbackSelectSupplier.SelectedItem as DisplayItems).Id;//Not using yet
        supplier.Name = (cmbFeedbackSelectSupplier.SelectedItem as DisplayItems).Name;

        DataGridTextColumn columnFeedbackSupplier = new DataGridTextColumn();
        columnFeedbackSupplier.Binding = new Binding("Supplier") { Mode = BindingMode.TwoWay };
        columnFeedbackSupplier.CanUserReorder = true;
        columnFeedbackSupplier.CanUserResize = true;
        columnFeedbackSupplier.IsReadOnly = false;

        columnFeedbackSupplier.Header = supplier.Name;

        dgFeedbackAddCost.SelectAll();

        IList list = dgFeedbackAddCost.SelectedItems as IList;
        IEnumerable<ViewQuoteItemList> items = list.Cast<ViewQuoteItemList>();

        var collection = new List<ExpandoObject>();
        foreach (var i in items)
        {
            dynamic a = new ExpandoObject();
            a.Id = (cmbFeedbackSelectSupplier.SelectedItem as DisplayItems).Id;
            a.Item = i.Item;
            a.Supplier = 25;
            collection.Add(a);
        }

        dgFeedbackSelectSupplier.Columns.Add(columnFeedbackSupplier);
        dgFeedbackSelectSupplier.ItemsSource = collection;
    }
like image 700
CareTaker22 Avatar asked Feb 05 '16 10:02

CareTaker22


1 Answers

May I propose another approach? From what I understand;

You have suppliers and these suppliers have items. You can add new suppliers. I assumed suppliers may not have all the items (for a challenge :)).

You want to present this data structure in a grid like view.

The problem here is that you are trying to display a non-tabular data with a tabular view component. What you have is hierarchical data. Before I continue with my solution here are some screen shots.

enter image description here

enter image description here

enter image description here

What I basically did here is to create new views on the hierarchical data, filling the gaps and turn it into a tabular form. I used fake classes for the empty slots so I could easily select the proper datatemplates in XAML. I avoided to use any custom code and kept everything in MVVM+XAML way. So bindings and such works as expected.

The new views had to be updated when the collections changed, so I used the messenger class from MVVMLight for easy implementation, and called RaisePropertyChanged events manually.

In XAML I used ItemsControl and UniformGrid components to create the grid like view.

I put the complete solution on GitHub: https://github.com/orhtun/GridLikeViewWithDynamicColumns

It creates random data on each run. If you get build errors, try right click on the solution and Restore NuGet Packages.

like image 129
Orhan Tuncer Avatar answered Oct 22 '22 13:10

Orhan Tuncer