Showing posts with label DataGrid. Show all posts
Showing posts with label DataGrid. Show all posts

Monday, June 2, 2014

Pitfalls of using WPF DataGrid

WPF DataGrid is a very powerful Control that was first published within the WPF Toolkit. Since .NET 4.0 the WPF DataGrid is part of the .NET Framework. The simplest way to use it, is to set the ItemsSource, only.
<DataGrid ItemsSource="{Binding Source1}" />
public ICollection<IValue> Source1 { getset; }
Due to the AutoGenerateColumns property, which default value is true, the DataGrid is created with the properties of the class that is used within the collection. In order that this works
  • the binded collection must be public
  • the properties of the used class must be public
For example the interface could look like that
public interface IValue
{
    string Val { get; }
    string Key { get; }
}
and the implementation of the interface could look like that
public class KeyVal : IValue
{
    public KeyVal(string key, string val)
    {
        Key = key;
        Val = val;
    }
 
    public string Val
    {
        get;
        private set;
    }
 
    public string Key
    {
        get;
        private set;
    }
}
All that results into

As you can see columns are auto-generated and filled with the objects of the binded list.
For just viewing collections this is all you have to consider. If you want also add new entries to the collection there must be done some changes. In the XAML part the CanUserAddRows property indicates if it is possible to add new entries. The default value is true, so the XAML part remains unchanged. In code we have to do some changes
  • the generic type of the collection must be a class (not an interface)
  • there must be a default constructor (parameterless) in the generic type of the collection
public ICollection<KeyVal> Source1 { getset; }
public class KeyVal : IValue
{
    public KeyVal()
    {
 
    }
 
    public KeyVal(string key, string val)
    {
        Key = key;
        Val = val;
    }
 
    public string Val
    {
        get;
        set;
    }
 
    public string Key
    {
        get;
        set;
    }
}
Only with these changes a new object can be created from the view and added to the collection. As result there is a new empty entry in the DataGrid that can be filled by the user and is then added to the collection.

Sunday, January 19, 2014

Award Winning TechNet Guru Article: Binding of DataGrid Column Header

I'm proud to announce that the article Binding of DataGrid Column Header has been awarded with the bronze medal at the TechNet Guru Awards - December 2013 in the section Windows Presentation Foundation (WPF).

Monday, December 30, 2013

WPF Binding of DataGrid Column Header in XAML

Dynamically binding to a column header of a DataGrid is not a transparently task. The problem is that the column header is not inheriting from FrameworkElement.

A simple solution to that problem is presented on the Developer Code Samples Gallery (Binding of DataGrid column header) and the TechNet Wiki (Binding of DataGrid Column Header).

There are several solutions for this problem. I will introduce the simplest solution (in my opinion). Since DataGridColumn does not inherit the DataContext of the superior element, you have to indicate the DataContext to use. This can be easily done as the following code snippet shows.
<DataGrid>
  <DataGrid.Columns>
    <DataGridTemplateColumn>
      <DataGridTemplateColumn.Header>
        <TextBlock Text="{Binding DataContext.HeaderNameText, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
      </DataGridTemplateColumn.Header>
    </DataGridTemplateColumn>
  </DataGrid.Columns>
<DataGrid>

As you can see the header is defined by using a TextBlock. The Text property of the TextBlock is bound to the property HeaderNameText of the DataContext of the DataGrid. In a similar way you could use your own DataContext for the DataGridColumns. By defining the header in this way you could further customize your header by using further elements, e.g. Images. The DataContext of the DataGrid is set in code.

Data data = new Data();
data.HeaderNameText = "Header2";
data.Items = new List<string>() { "Item1", "Item2" };
  
DataContext = data;

The DataContext is an own object containing the values of the DataGrid and the Header name.

public class Data
{
  public string HeaderNameText
  {
    get;
    set;
  }
  
  public List<string> Items
  {
    get;
    set;
  }
}