Deleting columns form WPF DataGrid

Mar 8, 2009 at 6:29 PM
Edited Mar 8, 2009 at 6:31 PM

I would like to remove a column from a datagrid on checkbox_unchecked event. Data gets binded to datagrid on checkbox_checked event. The way I do that is discussed in discussion under the following link:  http://wpf.codeplex.com/Thread/View.aspx?ThreadId=49067&ANCHOR#Post165072.  

Just in short:  I have a list of recipients. I would like to be able to assigne or remove different productcs to these recipients. So when a checkbox represnting certain product is checked a column is created in the datagrid. And when the check box is unchecked the adequate column should be removed.

Since I use binding I thought I could simply remove the product form the recipeint's list of product and refresh the datagird's Items list. Here is my solution: 

void cb_Unchecked(object sender, RoutedEventArgs e)
{
    try
    {
        CheckBox cb = sender as CheckBox;
        dtProdukti product = cb.Tag as dtProdukti;
        
OrderFinder predicate1 = new OrderFinder() { Product = product }; // I created A separate class to create a predicate I can pass a parameter

       foreach
(Prejemnik recipient1 in lstRecipients)
        {
            recipient1.ListOrders..RemoveAll(predicate1.findOrderByProdukt); // finds and removve all orders in the list of orders for each indivual recipient
        } 
 
         dgvOrdersWPF.Items.Refresh();  // refresh the items contained in the list of datagrid to reflect the changes made to the datasource (lstRecipients)
    }
    catch (Exception)
    {
        throw;
    }
}


The values in individual cells are deleted, but the column stays displayed. Further more when I add another product to the list. A new column is added, but values inserted get inserted into both the added column and the empty one. What am I doing wrong? 

Thank you for your help 

Best regards,
Jurij




 

Coordinator
Mar 9, 2009 at 6:51 PM
Hi Jurij,

Remember that the Column collection is not bound to the product list. Instead Cell's content corresponding to the column is bound to the each item in the list. Hence column still exists. You would have to remove column yourself. Also you should update Binding property of other columns, if the index of product they are using changes because of removing this product.
Mar 9, 2009 at 8:12 PM
Hello,

thank you for the advice. Taking this perspective I managed to solve the problem somehow. Eventhough I think, that my solution is to complicated for such a simple task as removing a column from the datagrid.:) The followwing is my solution. Loking forward to any comments.:)

void cb_Unchecked(object sender, RoutedEventArgs e)
{
    try
    {
        CheckBox cb = sender as CheckBox;
        dtProdukti product = cb.Tag as dtProdukti;
        
OrderFinder predicate1 = new OrderFinder() { Product = product }; // I created A separate class to create a predicate I can pass a parameter

       foreach
(Prejemnik recipient1 in lstRecipients) //cleans the unchecked product form the list od products for each customer individually
        {
            recipient1.ListOrders..RemoveAll(predicate1.findOrderByProdukt); // finds and remove all orders in the list of orders for each indivual recipient
        } 
 
        
        while (dgvNarocilaWPF.Columns.Count > 3) //removes all the columns but the first three . The fisrt three columns contain properties that can not be unchecked.:)
        {
            int i = dgvOrdersWPF.Columns.Count - 1;
            dgvOrdersWPF.Columns.RemoveAt(i);
        }
        
        foreach
(dtProdukti product1 in lstRecipients[0].ListOrders  //creates back the columns for different products that are still checked
        {                                                                                                        //takes the first reciepient in the list of recipients. Its list of products is then takend to create back the deleted columns that shouldn't have been deleted in the first placeat all
            int i = lstRecipients[0].ListOrders.IndexOf(product1);
            Binding myBinding = new Binding("ListOrders[" + i + "].Quantity");
            myBinding.Mode =
BindingMode.TwoWay;
            DataGridTextColumn clm = new DataGridTextColumn();
            clm.Binding = myBinding;
            
clm.Header = product1.Description
            dgvOrdersWPF.Columns.Add(clm);
        }

         dgvOrdersWPF.Items.Refresh();  // refresh the items contained in the list of datagrid to reflect the changes made to the datasource (lstRecipients)
    }
    catch (Exception)
    {
        throw;
    }
}



Best regards,
Jurij
Coordinator
Mar 10, 2009 at 1:19 AM
I think it is not necessary to remove and add all the columns. Instead you can find the index of the product for which column is removed and change the Binding property of all the columns following the removed column. This way you would have almost zero overhead if the column removed was the last.
Mar 10, 2009 at 7:45 PM
I have tried to delete just THE columns, but I found it very difficult to identify columns to link them back to products in code, since there is only column's header that descibes the column. What I used to do in nomal windows applications was that I named columns with some unique key - in this case it would have been products primary key form the database. That way I would be able to use any string for column's header and I would still know exactly which column belonged to each product. Even if two columns had the same header. However using this wpf datagrid I found it very difficult to link columns back to products. To be honest I can't even get the columns binding. So that I could update it. Now, when reading one of your previous post I realise this kind of trying is menaning less since the products for each individual customer are binded to each individual cell separately.  Even knowing this I can't find bindig relation for each individual cell.:)

That is why I decided for the solution where I din't have to know anything about columns binding. If everything worked fine the product objects in the orders list would get their values updated before the columns and their cells are deleted. This way no data is lost. I also maintain the display order of products that a user has establised by the products checking order.
 
I have to say that I was surprised how difficult it was to delete those columns. So much code.

Mar 11, 2009 at 8:37 AM
I don't know exactly where in the inheritance hierarchy it is introduced, but most (all?) UI elements have an (object) "Tag" property that can be used to store arbitrary data. Admittedly it is not type safe, but if you know that each DataGridColumn has an int value there, that might not be a big problem. Then you can simply run a foreach loop over the Columns collection until you find the appropriate one, remove it, and update the remaining ones.
Mar 11, 2009 at 12:25 PM
Hi!

As far as I know in wpf datagridcolumns do NOT have tag property.

I am aware of this option and I find it veryuseful, usually.:)
Mar 11, 2009 at 1:12 PM
Oops. My apologies - I should have checked beforehand. You are right.
Mar 11, 2009 at 2:08 PM
Hey, no problem. Any comments, suggestions are more than welcome.
Coordinator
Mar 11, 2009 at 6:16 PM
You can create an attached property somewhere in your app and set it value for the columns you create to your key. And use the same attached property to identify your columns. It is as good as Tag :)