Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add data-binding for DataGridTemplateColumn created in code

The question:

Is there a way to define a DataTemplate in XAML and instantiate it in code (rather than retrieve singleton by FindResource) and modify its VisualTree before sending to where a DataTemplate is required such as DataGridTemplateColumn.CellTemplate?

Background:

I am displaying a 2-dimensional array data[][] in a DataGrid by adding DataGridTemplateColumn columns on my own and there is a DataTemplate defined in XAML that knows how to present each element in the array. However the default DataContext for each cell is the row, i.e. data[x]. So I need to "parameterize" the DataTemplate for each column by setting the root visual element's DataContext to binding "[y]" where y is the column index. Currently the DataTemplate is defined as in DataGrid.Resources and retrieved by FindResource() which is returning the same instance every time. Besides calling LoadContent() gives me the UIElement tree rather than loading the VisualTree on the DataTemplate itself. I am looking for a way to instantiate the DataTemplate in code, do the desired modification and set to DataGridTemplateColumn.CellTemplate.

like image 801
NS.X. Avatar asked Dec 22 '12 07:12

NS.X.


2 Answers

Inspired by Sisyphe's answer, I found this more portable solution:

public class DataGridBoundTemplateColumn : DataGridTemplateColumn
{
    public string BindingPath { get; set; }

    protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
    {
        var element = base.GenerateEditingElement(cell, dataItem);
        element.SetBinding(ContentPresenter.ContentProperty, new Binding(this.BindingPath));
        return element;
    }

    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
    {
        var element = base.GenerateElement(cell, dataItem);
        element.SetBinding(ContentPresenter.ContentProperty, new Binding(this.BindingPath));
        return element;
    }
}

Usage:

var cellTemplate = (DataTemplate)this.dataGrid.FindResource("cellTemplate");
foreach (var c in data.Columns)
{
    var col = new DataGridBoundTemplateColumn
    {
        Header = c.HeaderText,
        CellTemplate = cellTemplate,
        BindingPath = string.Format("[{0}]", c.Index)
    };

    this.dataGrid.Columns.Add(col);
}

Hope this helps someone who has the same requirement as the one in my question.

like image 189
NS.X. Avatar answered Oct 27 '22 15:10

NS.X.


(templateKey as DataTemplate).LoadContent()

Description: When you call LoadContent, the UIElement objects in the DataTemplate are created, and you can add them to the visual tree of another UIElement.

like image 32
Reza ArabQaeni Avatar answered Oct 27 '22 15:10

Reza ArabQaeni