Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF MvvM DataGrid Dynamic Columns

Tags:

mvvm

wpf

datagrid

I am searching about how to create the columns of the DataGrid from the ToolKit dynamic in MvvM way. But looks like it is impossible !

Is there some one that had to do the samething ?

there is no need to create a usercontrol or another control that comes from DataGrid, I just want to set de ItemSource of the grid to my custom object and in some point I want to define the columns of the grid in runtime dynamic based in the kind of the object.

Is that possible ?

cheers

like image 493
2Fast4YouBR Avatar asked Jun 17 '10 21:06

2Fast4YouBR


2 Answers

I'm going to preface this by saying it maybe isn't the best solution to be doing and may not work in some situations but you can give it a try and see if it will work for what you want. I just whipped this up so it may have some bugs in it. Its still going to involve some code, but it keeps your model from knowing about you view.

What you need to do is create an extension property that will allow you to bind the Columns property on the DataGrid. Here is an example that I put together.

using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;

public static class DataGridExtension
{
    public static ObservableCollection<DataGridColumn> GetColumns(DependencyObject obj)
    {
        return (ObservableCollection<DataGridColumn>)obj.GetValue(ColumnsProperty);
    }

    public static void SetColumns(DependencyObject obj, ObservableCollection<DataGridColumn> value)
    {
        obj.SetValue(ColumnsProperty, value);
    }

    public static readonly DependencyProperty ColumnsProperty =  
           DependencyProperty.RegisterAttached("Columns",
           typeof(ObservableCollection<DataGridColumn>),
           typeof(DataGridExtension),
           new UIPropertyMetadata (new ObservableCollection<DataGridColumn>(),
           OnDataGridColumnsPropertyChanged));


    private static void OnDataGridColumnsPropertyChanged(
           DependencyObject d,
           DependencyPropertyChangedEventArgs e)
    {
        if (d.GetType() == typeof(DataGrid))
        {
            DataGrid myGrid = d as DataGrid;

            ObservableCollection<DataGridColumn> Columns = 
                 (ObservableCollection<DataGridColumn>)e.NewValue;

            if(Columns != null)
            {
                myGrid.Columns.Clear();

                if (Columns != null && Columns.Count > 0)
                {
                    foreach (DataGridColumn dataGridColumn in Columns)
                    {
                        myGrid.Columns.Add(dataGridColumn);
                    }
                }


                Columns.CollectionChanged += delegate(object sender,
                                 NotifyCollectionChangedEventArgs args)
                     {
                       if(args.NewItems != null)
                       {
                         foreach (DataGridColumn column 
                              in args.NewItems.Cast<DataGridColumn>())
                         {
                             myGrid.Columns.Add(column);
                         }
                       }

                       if(args.OldItems != null)
                       {
                         foreach (DataGridColumn column 
                                 in args.OldItems.Cast<DataGridColumn>())
                         {
                           myGrid.Columns.Remove(column);
                         }
                       }
                    };
            }
        }
    }
}

Then you attach it to you DataGrid like this (Where columns is the an ObservableCollection property on your view model)

<Controls:DataGrid AutoGenerateColumns="False" 
            DataGridExtension.Columns="{Binding Columns}" />

I'm not sure how well it is going to respond if you start adding and remove columns, but it seems to work from my basic testing. Good Luck!

like image 70
ctrlalt313373 Avatar answered Sep 25 '22 15:09

ctrlalt313373


Having a similar problem, I did not want to add another dependency property. My workaround was to organise the data to display in the DataGrid in a DataTable and bind the DataGrid ItemSource property to this DataTable (with of course AutoGenerateColumns set to true).

It works well, DataGrids seem happy with DataTable as source.

like image 43
user3189858 Avatar answered Sep 25 '22 15:09

user3189858