How to hide wpf datagrid columns depending on a property
A column in a datagrid is an abstract object which does not appear in the visual tree, thus you cannot use RelativeSource
-binding, ElementName
will not work either since it will not find a governing FrameworkContentElement so you are in kind of a bind.
One way that works is via Source
and x:Reference
, for that you will need to name your window and move the column to its resources to avoid a cyclical dependency error:
<Window Name="_window" ...>
<Window.Resources>
<DataGridTextColumn x:Key="ThatPeskyColumn"
Binding="{Binding Size}"
Visibility="{Binding DataContext.Flag, Source={x:Reference _window}, Converter={StaticResource BoolToVis}}"/>
</Window.Resources>
<!-- ... -->
<DataGrid AutoGenerateColumns="False" Name="Blumen"
ItemsSource="{Binding Leaves}">
<DataGrid.Columns>
<StaticResource ResourceKey="ThatPeskyColumn"/>
<!-- ... -->
Great fun.
Hide Datagrid Column based on its Property name
You could handle the DataGrid.AutoGeneratedColumns
Event and set the column's Visibility
property from there. You should be able to do something like this:
private void DataGridAutoGeneratingColumn(object sender,
DataGridAutoGeneratingColumnEventArgs e)
{
DataGrid dataGrid = sender as DataGrid;
if (dataGrid != null && IsBKM) dataGrid.Columns[0].Visible = false;
}
UPDATE >>>
You can use the e.Column.Header
property to check the name of the column and then use that instead. However, your column has no Header
currently set. You could also set the column name (in XAML) and then check for that Name
value instead of using the Header
property:
private void DataGridAutoGeneratingColumn(object sender,
DataGridAutoGeneratingColumnEventArgs e)
{
if (e.Column.Name == "IsBKM" && IsBKM)
{
e.Column.Visibility = Visibility.Collapsed;
}
}
Hide a Column from a DataGrid when the ItemSource is an Observable Collection
This issue will happen regardless of whether the data resides in an ObservableCollection
or not.
To correct this, one must set the grid to not auto generate the columns. That is done by setting the property AutoGenerateColumns=False
and then in the xaml specify the columns desired.
<DataGrid ItemsSource="{Binding MyData}" AutoGenerateColumns="False" >
<DataGrid.Columns>
<DataGridTextColumn Header="The Code"
Binding="{Binding Code}"/>
<DataGridTextColumn Header="The Name"
Binding="{Binding Name}"/>
<DataGridTextColumn Header="The Type"
Binding="{Binding Type}"/>
</DataGrid.Columns>
</DataGrid>
Check out more column options in the documentation for the DataGrid.
Show/Hide DataGrid Columns XAML
Was able to find some more information on this. This link has a good answer/explanation.
datagridtextcolumn-visibility-binding
It turns out that the columns of a DataGrid do not appear in the visual tree of a DataGrid.
But the answer is to use x:reference in the visibility binding, and a BooleanToVisibilityConverter:
<DataGridTextColumn Header="Customer #" x:Name="CustNum_Col" Visibility="{Binding Source={x:Reference VisibilityCheck}, Path=IsChecked,Converter={StaticResource ObjectToVisibilityConverter}}" />
Visual Studio will show the squiggly line under the binding saying that "object not set to instance of an object" but it this still appears to work.
MVVM - Hide Datagrid column based on column name with autogeneratecolumns = True
I found a solution by applying this style:
<Style x:Key="ColumnStyle" TargetType="DataGridColumnHeader">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Value}" Value="id">
<Setter Property="Visibility" Value="Hidden"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
to DataGridCell
and to DataGridColumnHeader
and allocating the column in the end of the table this removed the empty column from the middle of the table.
Hiding DataGrid Column based on Column values
You need to check each value in the DataGridTextColumn
and set Column.Visibility
accordingly.
To wrap all the logic I've derived from DataGrid.
public class MyDataGrid : DataGrid
{
private void ValidateColumnVisibility()
{
if (Items.Count == 0 || Items[0] == CollectionView.NewItemPlaceholder) return;
var itemClass = Items[0].GetType();
foreach (var column in Columns)
{
if (column.GetType() == typeof(DataGridTextColumn))
{
// find the property that this column is bound to
DataGridBoundColumn boundColumn = column as DataGridBoundColumn;
Binding binding = boundColumn.Binding as Binding;
string boundPropertyName = binding.Path.Path;
var prop = itemClass.GetProperty(boundPropertyName);
// Validating Column.Visibility when first value is null
// when all values are null -> Visibility.Collapsed
// bound value not a string -> Visibility.Visible
// all bound strings empty -> Visibility.Collapsed
if (prop.GetValue(Items[0]) == null)
{
column.Visibility = Visibility.Collapsed;
foreach (var item in Items)
{
if (item != CollectionView.NewItemPlaceholder)
{
if (prop.GetValue(item) != null)
{
if (prop.GetValue(item).GetType() != typeof(String))
column.Visibility = Visibility.Visible;
else if (String.IsNullOrEmpty(prop.GetValue(item) as String) == false)
column.Visibility = Visibility.Visible;
}
}
}
}
// First value not null and all bound strings empty -> Visibility.Collapsed
else if (prop.GetValue(Items[0]).GetType() == typeof(String))
{
column.Visibility = Visibility.Collapsed;
foreach (var item in Items)
{
if (item != CollectionView.NewItemPlaceholder)
{
if (String.IsNullOrEmpty(prop.GetValue(item) as String) == false)
column.Visibility = Visibility.Visible;
}
}
}
}
}
}
protected override void OnItemsSourceChanged(
IEnumerable oldValue, IEnumerable newValue)
{
base.OnItemsSourceChanged(oldValue, newValue);
ValidateColumnVisibility();
}
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
{
base.OnItemsChanged(e);
ValidateColumnVisibility();
}
}
Using MyDataGrid
you no longer need to set Column.Visibility
in XAML as it happens automagically.
Related Topics
Why Is There Huge Performance Hit in 2048X2048 Versus 2047X2047 Array Multiplication
C# Reflection - Load Assembly and Invoke a Method If It Exists
Change the Value in App.Config File Dynamically
Convert an Object to an Xml String
Threadpool.Queueuserworkitem VS Task.Factory.Startnew
Will a Future Version of .Net Support Tuples in C#
Improve Wpf Datagrid Performance
How to Send an Email in .Net According to New Security Policies
How to Add an Ampersand for a Value in a ASP.NET/C# App Config File Value
Changing the Cursor in Wpf Sometimes Works, Sometimes Doesn'T
Jobject.Parse VS JSONconvert.Deserializeobject
How to Make an Installer for My C# Application
How to Reduce Memory Consumption of PDFptable with Many Cells