I have a grid in WPF, auto-generating columns. How can I dynamically hide columns using data annotations?
I thought of having a property in my model to specify whether the column is visible, but I'm not sure how to do it.
My model, bound to the grid:
public class Template
{
public string County { get; set; }
public string Operator { get; set; }
public string Field { get; set; }
}
Here is a sample which uses attributes to hide columns. It uses an attached property to handle the AutoGeneratingColumn
event.
HideColumnIfAutoGenerated.cs - Attribute
namespace AutoHideColumn
{
public class HideColumnIfAutoGenerated : System.Attribute
{
public HideColumnIfAutoGenerated()
{
}
}
}
DataGridExtension.cs - Attached Property
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace AutoHideColumn
{
public static class DataGridExtension
{
public static readonly DependencyProperty HideAnnotatedColumnsProperty = DependencyProperty.RegisterAttached(
"HideAnnotatedColumns",
typeof(bool),
typeof(DataGridExtension),
new UIPropertyMetadata(false, OnHideAnnotatedColumns));
public static bool GetHideAnnotatedColumns(DependencyObject d)
{
return (bool)d.GetValue(HideAnnotatedColumnsProperty);
}
public static void SetHideAnnotatedColumns(DependencyObject d, bool value)
{
d.SetValue(HideAnnotatedColumnsProperty, value);
}
private static void OnHideAnnotatedColumns(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
bool hideAnnotatedColumns = (bool)e.NewValue;
DataGrid dataGrid = d as DataGrid;
if (hideAnnotatedColumns)
{
dataGrid.AutoGeneratingColumn += dataGrid_AutoGeneratingColumn;
}
else
{
dataGrid.AutoGeneratingColumn -= dataGrid_AutoGeneratingColumn;
}
}
private static void dataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
PropertyDescriptor propertyDescriptor = e.PropertyDescriptor as PropertyDescriptor;
if (propertyDescriptor != null)
{
foreach (var item in propertyDescriptor.Attributes)
{
if (item.GetType() == typeof(HideColumnIfAutoGenerated))
{
e.Cancel = true;
}
}
}
}
}
}
XAML
<Window x:Class="AutoHideColumn.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:AutoHideColumn"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<DataGrid Name="dg" local:DataGridExtension.HideAnnotatedColumns="True">
</DataGrid>
<DataGrid Grid.Row="1" Name="dg1">
</DataGrid>
</Grid>
</Window>
CodeBehind
using System.Collections.Generic;
using System.Windows;
namespace AutoHideColumn
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.dg.ItemsSource = new List<Customer>();
this.dg1.ItemsSource = new List<Customer>();
}
}
public class Customer
{
[HideColumnIfAutoGenerated()]
public int ID { get; set; }
public string Name { get; set; }
}
}
Try this
public partial class MainWindow : Window
{
private List<string> visibleColumns;
public MainWindow()
{
InitializeComponent();
InitializeList();
visibleColumns = GetVisibleColumns();
dg.AutoGeneratingColumn += dg_AutoGeneratingColumn;
dg.ItemsSource = Templates;
}
void dg_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
if(!visibleColumns.Contains(e.Column.Header.ToString()))
e.Column.Visibility=Visibility.Collapsed;
}
List<string> GetVisibleColumns()
{
return typeof(Template).GetProperties()
.Where(p =>
p.GetCustomAttributes(typeof(Visible), true)
.Where(ca => ((Visible)ca).IsVisible).Any()
).Select(s => s.Name).ToList();
}
private void InitializeList()
{
Templates = new List<Template>();
Templates.Add(new Template { County = "abc", Operator = "123", Field = "xyz" });
Templates.Add(new Template { County = "abc", Operator = "123", Field = "xyz" });
Templates.Add(new Template { County = "abc", Operator = "123", Field = "xyz" });
Templates.Add(new Template { County = "abc", Operator = "123", Field = "xyz" });
}
public List<Template> Templates { get; set; }
}
>Template Class
public class Template
{
[Visible(false)]
public string County { get; set; }
[Visible(true)]
public string Operator { get; set; }
[Visible(true)]
public string Field { get; set; }
}
>Visible Attribute
public class Visible : Attribute
{
public Visible(bool isVisible)
{
IsVisible = isVisible;
}
public bool IsVisible { get; set; }
}
>xaml
<Grid>
<DataGrid AutoGenerateColumns="True" x:Name="dg"/>
</Grid>
this would be by far the most simplistic workaround which comes close to data annotation: omit the getter and setter.
public class Template
{
public string County { get; set; }
public string Operator { get; set; }
public string Field; //This is now a field and not a property-> invisible in datadrid
}
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