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.
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
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With