Introduction
Sometimes we need to hide automatically columns that doesn’t have values in a datagrid. Not only the column visibility property cannot be bound in simple manner, but hiding it in runtime mode is a bit complex.
In fact, the datagrid columns are not part of visual or logical tree because they are abstract and so, binding the visibility property will be achieved with a little “verbosity coding”.
Using the code
First of all, let extend a grid column property like this
public class DataGridTextColumnExtended : DataGridTextColumn
{
public static readonly DependencyProperty VisibiltyBindingProperty = DependencyProperty.Register(
"VisibiltyBinding", typeof(Visibility), typeof(DataGridTextColumnExtended),
new PropertyMetadata(OnVisibilityChanged));
private static void OnVisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((DataGridTextColumnExtended)d).Visibility = (Visibility)e.NewValue;
}
public Visibility VisibiltyBinding
{
get { return (Visibility)GetValue(VisibiltyBindingProperty); }
set { SetValue(VisibiltyBindingProperty,
In my case, I just extend the DataGridTextColumn class, it’s recommended to use DataGridTemplateColumn instead as this class can contains more than simple text.
I create a dependency property to handle the visibility of the column. This one can now be bound on runtime without XamlParseException.
But, as we can only use a static datasource when binding, then I create a dependency object which behave as proxy.
public class DataContextProxy : DependencyObject
{
public static readonly DependencyProperty DataSoureceProperty =
DependencyProperty.Register(
"DataSource", typeof(object), typeof(DataContextProxy),
new PropertyMetadata(new PropertyMetadata(null)));
public object DataSource
{
get { return this.GetValue(DataSoureceProperty); }
set { this.SetValue(DataSoureceProperty, value); }
}
}
So, I could define a static resource in my view which is bound on my datasource: just like this
<helpers:DataContextProxy x:Key="DataProxy" DataSource="{Binding DataListModified}"/>
From now, I can use it as a source to bind the visibility of my grid column with a converter. The converter takes the datasource as value, and the column name as parameter; and with reflection, I use to determine if all rows of the column are empty or not.
public class GridRowVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null || parameter == null)
{
return Visibility.Visible;
}
var data = value as IEnumerable<Person>;
if (data != null)
{
var noEmpty = from d in data
let v = d.GetType().GetProperty(parameter.ToString()).GetValue(d, null)
where v != null && !string.IsNullOrEmpty(v.ToString())
select d;
return noEmpty.Any() ? Visibility.Visible : Visibility.Collapsed;
}
return Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Finally, the binding on the visibility of the grid column can be done as follow
<helpers:DataGridTextColumnExtended
Header="Phone number"
VisibiltyBinding="{Binding Source={StaticResource DataProxy},Path=DataSource,Converter={StaticResource GridRowVisibilityConverter}, ConverterParameter='Phone'}"
Binding="{Binding Phone}"/>
The source code can be found on this link: https://github.com/katoyi/SLWPFGrid.
Points of Interest
The main interesting part of this article is the converter class. In fact, the visibility can be managed in a classic MVVM by doing all check on datasource in the ViewModel, and bind the column visibility after all computation made in the ViewModel. This means having additionnal variables (one variable per column to hide).
History