joek1975
joek1975

Reputation: 3583

Hide a Column Using Data Annotations in WPF

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

Answers (4)

Falco Alexander
Falco Alexander

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

Anand Murali
Anand Murali

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

Anand Murali
Anand Murali

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

yo chauhan
yo chauhan

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

Related Questions