Reputation: 3583
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; }
}
Upvotes: 6
Views: 3100
Reputation: 3332
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
}
Upvotes: 2
Reputation: 4109
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; }
}
}
Upvotes: 6
Reputation: 4109
Attributes cannot be changed at run time hence you cannot dynamically hide columns using data annotations. But it is possible to dynamically hide columns. Here is an example which demonstrates it.
XAML
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<DataGrid ItemsSource="{Binding AutoGenerateColumnDetails}" CanUserAddRows="False" CanUserDeleteRows="False">
</DataGrid>
<Button Grid.Row="1" Content="Refresh" Click="Button_Click" HorizontalAlignment="Left" Margin="5"/>
<DataGrid Name="dg" Grid.Row="2" ItemsSource="{Binding TemplateList}" AutoGeneratingColumn="dg_AutoGeneratingColumn">
</DataGrid>
</Grid>
Code behind
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
namespace AutoHideDGColumn
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ViewModel _ViewModel = null;
public MainWindow()
{
InitializeComponent();
_ViewModel = new ViewModel();
this.DataContext = _ViewModel;
}
private void dg_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
if (_ViewModel.AutoGenerateColumnDetails.Where(d => d.HideColumn == true).Select(d => d.PropertyName).ToList().Contains(e.PropertyName))
e.Cancel = true;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// Reset to trigger AutoGeneratingColumn event
this.dg.AutoGenerateColumns = false;
this.dg.AutoGenerateColumns = true;
}
}
public class ViewModel
{
private List<Template> _TemplateList;
public List<Template> TemplateList
{
get { return _TemplateList; }
set { _TemplateList = value; }
}
private List<AutoGenerateColumnDetail> _AutoGenerateColumnDetails;
public List<AutoGenerateColumnDetail> AutoGenerateColumnDetails
{
get { return _AutoGenerateColumnDetails; }
set { _AutoGenerateColumnDetails = value; }
}
public ViewModel()
{
AutoGenerateColumnDetails = typeof(Template).GetProperties().Select(p => new AutoGenerateColumnDetail() { PropertyName = p.Name }).ToList();
TemplateList = new List<Template>()
{
new Template() { County = "Count1", Field = "Field1", Operator = "Operator1"},
new Template() { County = "Count2", Field = "Field2", Operator = "Operator2"},
new Template() { County = "Count3", Field = "Field2", Operator = "Operator3"},
};
}
}
public class Template
{
public string County { get; set; }
public string Operator { get; set; }
public string Field { get; set; }
}
public class AutoGenerateColumnDetail
{
public string PropertyName { get; set; }
public bool HideColumn { get; set; }
}
}
Upvotes: 0
Reputation: 12295
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>
Upvotes: 2