Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hide a Column from a DataGrid when the ItemSource is an Observable Collection

I have a DataGrid where the ItemSource is an Observable Collection bound using MVVM archetype. I would like to not show the ID property of the class displayed in my DataGrid however I still need the property to exist.

My Code:

XAML

<DataGrid ItemsSource="{Binding MyData}" IsReadOnly="True" Name="dtSearch" />

View Model

    private ObservableCollection<MyDataClass> myData;
    public ObservableCollection<MyDataClass> MyData
    {
        get { return myData; }
        set
        {
            myData= value;
            RaisePropertyChanged("MyData");
        }
    }

Observable Class

public partial class MyDataClass
{
    public int ID { get; set; }
    public string Code { get; set; }
    public string Name { get; set; }
    public string Type { get; set; }
}

Is there an attribute I can give my ID property to hide it from the DataGrid?

Do I need to create another class for visible properties?

like image 894
Ryan Searle Avatar asked Aug 24 '15 15:08

Ryan Searle


3 Answers

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.

like image 54
ΩmegaMan Avatar answered Oct 04 '22 06:10

ΩmegaMan


WPF data binding engine binds to all public properties of the object. So, the simplest is to make your ID property internal (if that doesn't break any other code).
However, there is a more general approach when binding to a list of objects. First, put the following in some common place:

public class BindableCollection<T> : ObservableCollection<T>, ITypedList
{
    string ITypedList.GetListName(PropertyDescriptor[] listAccessors) { return null; }
    PropertyDescriptorCollection ITypedList.GetItemProperties(PropertyDescriptor[] listAccessors)
    {
        return TypeDescriptor.GetProperties(typeof(T), PropertyFilter);
    }
    static readonly Attribute[] PropertyFilter = { BrowsableAttribute.Yes };
}

and use that class instead of ObservableCollection<T>. Then just use Browsable attribute to hide members of the item class. For your example it's something like this:

View Model

private BindableCollection<MyDataClass> myData;
public BindableCollection<MyDataClass> MyData
{
    get { return myData; }
    set
    {
        myData= value;
        RaisePropertyChanged("MyData");
    }
}

Observable Class

public partial class MyDataClass
{
    [Browsable(false)]
    public int ID { get; set; }
    public string Code { get; set; }
    public string Name { get; set; }
    public string Type { get; set; }
}
like image 21
Ivan Stoev Avatar answered Oct 04 '22 08:10

Ivan Stoev


XAML:

  <DataGrid x:Name="dataGrid1" Margin="0" AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Name}" Header="Name"/>
                <DataGridTextColumn Binding="{Binding Code}" Header="Code"/>
                <DataGridTextColumn Binding="{Binding Type}" Header="Type"/>
            </DataGrid.Columns>
   </DataGrid>

Code behind:

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        ObservableCollection<MyDataClass> data = new ObservableCollection<MyDataClass>();
        data.Add(new MyDataClass { Code = "Code 1", ID = 1, Name = "Name 1", Type = "Type 1" });
        data.Add(new MyDataClass { Code = "Code 2", ID = 2, Name = "Name 2", Type = "Type 2" });
        data.Add(new MyDataClass { Code = "Code 3", ID = 3, Name = "Name 3", Type = "Type 3" });
        data.Add(new MyDataClass { Code = "Code 4", ID = 4, Name = "Name 4", Type = "Type 4" });
        data.Add(new MyDataClass { Code = "Code 5", ID = 5, Name = "Name 5", Type = "Type 5" });

        dataGrid1.ItemsSource = data;
    }

Result:

enter image description here

like image 25
jsanalytics Avatar answered Oct 04 '22 08:10

jsanalytics