Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to stop a specific column to be generated in DataGrid when the AutoGenerateColumns is set to True?

I have bound a ObservableCollection to a DataGrid and set the AutoGenerateColumns to true in a WPF with MVVM application.

Then how can I stop a specific column to be appeared in the DataGrid?

I have seen a same question here. But I'm looking for more MVVM approach.

like image 475
Haritha Avatar asked Apr 05 '13 09:04

Haritha


2 Answers

MVVM means your UI and your Data layers are completely separate, with the View layer merely being a visual reflection of your Data layer.

So the "MVVM way" of excluding a column depends on where this exclusion should occur:

  • If your Data layer is supposed to exclude a column, remove that column from the data layer.

    This typically means modifying the collection your DataGrid.ItemsSource is binding to so it no longer includes the data that should not be visible.

    Or depending on what your application is for and what counts as "application logic", it may mean maintaining a string or List<string> of columns to exclude, and have the View find some way of binding to those strings and modifying it's display to exclude those columns (a custom dependency property, a converter, re-use of the Tag property + AutoGeneratingColumn event, triggers, etc)

  • If your View layer is supposed to exclude a column, remove that column from the view layer.

    This is usually done by setting AutoGenerateColumns="False" and specifying your <DataGrid.Columns> yourself, however you can also exclude the column from the View layer using the AutoGeneratingColumn event of the DataGrid, and cancelling the generation of the column if it's ColumnName equals to the value you want to exclude, like the question you linked suggested.

    private void DataGrid_AutoGeneratingColumn(
        object sender, DataGridAutoGeneratingColumnEventArgs e)
    {
        if ((string)e.Column.Header == "ID")
        {
            e.Cancel = true;
        }
    }
    

Remember, the whole point of MVVM is to separate your UI and Data layers. There's absolutely nothing wrong with using code-behind the view in MVVM, providing that code is related to UI-specific logic only, and not data/application-specific logic

like image 160
Rachel Avatar answered Oct 30 '22 01:10

Rachel


Or you could do this...

You can usually work around this using attached properties to bind events to Command-s - and then straight to your view-model.

namespace YourNamespace // wrap that into e.g. 'xmlns:local="clr-namespace:YourNamespace"'
public static class Attach
{
    public static ICommand GetAutoGenerateColumnEvent(DataGrid grid) { return (ICommand)grid.GetValue(AutoGenerateColumnEventProperty); }
    public static void SetAutoGenerateColumnEvent(DataGrid grid, ICommand value) { grid.SetValue(AutoGenerateColumnEventProperty, value); }
    public static readonly DependencyProperty AutoGenerateColumnEventProperty =
        DependencyProperty.RegisterAttached("AutoGenerateColumnEvent", typeof(ICommand), typeof(Attach), new UIPropertyMetadata(null, OnAutoGenerateColumnEventChanged));
    static void OnAutoGenerateColumnEventChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
    {
        DataGrid grid = depObj as DataGrid;
        if (grid == null || e.NewValue is ICommand == false)
            return;
        ICommand command = (ICommand)e.NewValue;
        grid.AutoGeneratingColumn += new EventHandler<DataGridAutoGeneratingColumnEventArgs>((s, args) => OnAutoGeneratingColumn(command, s, args));
        // handle unsubscribe if needed
    }
    static void OnAutoGeneratingColumn(ICommand command, object sender, DataGridAutoGeneratingColumnEventArgs e)
    {
        if (command.CanExecute(e)) command.Execute(e);
    }
}

And in your XAML...

<DataGrid 
    local:Attach.AutoGenerateColumnEvent="{Binding AutoGeneratingColumnCommand}" AutoGenerateColumns="True" />  

And in your view-model...

RelayCommand _autoGeneratingColumnCommand;
public RelayCommand AutoGeneratingColumnCommand 
{ 
    get 
    { 
        return _autoGeneratingColumnCommand ?? (_autoGeneratingColumnCommand = new RelayCommand(param => 
        { 
            var e = param as DataGridAutoGeneratingColumnEventArgs;
            if (e != null)
            {
                switch (e.PropertyName)
                {
                    case "ID":
                        e.Cancel = true;
                        break;
                    default:
                        break;
                }
            }
        }, 
        param => true)); 
    } 
}

...where RelayCommand : ICommand implementation you can find on the web (widely used)

like image 27
NSGaga-mostly-inactive Avatar answered Oct 30 '22 01:10

NSGaga-mostly-inactive