How to bind DataGridColumn.Visibility?
binding, datagrid, silverlight, visibility
Solution
Here's the solution I've come up with using a little hack.
First, you need to inherit from DataGrid.
public class DataGridEx : DataGrid
{
public IEnumerable<string> HiddenColumns
{
get { return (IEnumerable<string>)GetValue(HiddenColumnsProperty); }
set { SetValue(HiddenColumnsProperty, value); }
}
public static readonly DependencyProperty HiddenColumnsProperty =
DependencyProperty.Register ("HiddenColumns",
typeof (IEnumerable<string>),
typeof (DataGridEx),
new PropertyMetadata (HiddenColumnsChanged));
private static void HiddenColumnsChanged(object sender,
DependencyPropertyChangedEventArgs args)
{
var dg = sender as DataGrid;
if (dg==null || args.NewValue == args.OldValue)
return;
var hiddenColumns = (IEnumerable<string>)args.NewValue;
foreach (var column in dg.Columns)
{
if (hiddenColumns.Contains ((string)column.GetValue (NameProperty)))
column.Visibility = Visibility.Collapsed;
else
column.Visibility = Visibility.Visible;
}
}
}
The DataGridEx class adds a new DP for hiding columns based on the x:Name of a DataGridColumn and its descendants.
To use in your XAML:
<my:DataGridEx x:Name="uiData"
DataContext="{Binding SomeDataContextFromTheVM}"
ItemsSource="{Binding Whatever}"
HiddenColumns="{Binding HiddenColumns}">
<sdk:DataGridTextColumn x:Name="uiDataCountOfItems">
Header="Count"
Binding={Binding CountOfItems}"
</sdk:DataGridTextColumn>
</my:DataGridEx>
You need to add these to your ViewModel or whatever data context you use.
private IEnumerable<string> _hiddenColumns;
public IEnumerable<string> HiddenColumns
{
get { return _hiddenColumns; }
private set
{
if (value == _hiddenColumns)
return;
_hiddenColumns = value;
PropertyChanged (this, new PropertyChangedEventArgs("HiddenColumns"));
}
}
public void SomeWhereInYourCode ()
{
HiddenColumns = new List<string> {"uiDataCountOfItems"};
}
To unhide, you only need to remove the corresponding name from the list or recreate it without the unhidden name.
Problem
I have an issue similar to the following post: Silverlight DataGridTextColumn Binding Visibility I need to have a Column within a Silverlight DataGrid be visibile/collapsed based on a value within a ViewModel. To accomplish this I am attempting to Bind the Visibility property to a ViewModel. However I soon discovered that the Visibility property is not a DependencyProperty, therefore it cannot be bound. To solve this, I attempted to subclass my own DataGridTextColumn. With this new class, I have created a DependencyProperty, which ultimately pushes the changes to the DataGridTextColumn.Visibility property. This works well, if I don't databind. The moment I databind to my new property, it fails, with a AG_E_PARSER_BAD_PROPERTY_VALUE exception. ``` public class MyDataGridTextColumn : DataGridTextColumn { #region public Visibility MyVisibility public static readonly DependencyProperty MyVisibilityProperty = DependencyProperty.Register("MyVisibility", typeof(Visibility), typeof(MyDataGridTextColumn), new PropertyMetadata(Visibility.Visible, OnMyVisibilityPropertyChanged)); private static void OnMyVisibilityPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var @this = d as MyDataGridTextColumn; if (@this != null) { @this.OnMyVisibilityChanged((Visibility)e.OldValue, (Visibility)e.NewValue); } } private void OnMyVisibilityChanged(Visibility oldValue, Visibility newValue) { Visibility = newValue; } public Visibility MyVisibility { get { return (Visibility)GetValue(MyVisibilityProperty); } set { SetValue(MyVisibilityProperty, value); } } #endregion public Visibility MyVisibility } ``` Here is a small snippet of the XAML. ``` <DataGrid ....> <DataGrid.Columns> <MyDataGridTextColumn Header="User Name" Foreground="#FFFFFFFF" Binding="{Binding User.UserName}" MinWidth="150" CanUserSort="True" CanUserResize="False" CanUserReorder="True" MyVisibility="{Binding Converter={StaticResource BoolToVisibilityConverter}, Path=ShouldShowUser}"/> <DataGridTextColumn .../> </DataGrid.Columns> </DataGrid> ``` A couple important facts. - The Converter is indeed defined above in the local resources. - The Converter is correct, it is used many other places in the solution. - If I replace the {Binding} syntax for the MyVisibility property with "Collapsed" the Column does in fact disappear. - If I create a new DependencyProperty (i.e. string Foo), and bind to it I receive the AG_E_PARSER_BAD_PROPERTY_VALUE exception too. Does anybody have any ideas as to why this isn't working?