可绑定动态DataGrid列

时间:2013-05-23 07:14:41

标签: wpf dynamic datagridcolumn bindable

这是我的ViewModel类:

public class ColumnViewModel : ViewModelBase
{
    private string bindingPropName;
    public string BindingPropName
    {
        get { return bindingPropName; }

        set
        {
            if (bindingPropName != value)
            {
                bindingPropName = value;
                RaisePropertyChanged("BindingPropName");
            }
        }
    }

    private string header;
    public string Header
    {
        get { return header; }

        set
        {
            if (header != value)
            {
                header = value;
                RaisePropertyChanged("Header");
            }
        }
    }
}

DataGrid扩展类:

public static class DataGridColumns
{
    static DataGridColumns()
    {
        FrameworkElement.DataContextProperty.AddOwner(typeof(DataGridTextColumn));
    }

    private static readonly DependencyProperty DataGridColumnSettingsProperty = DependencyProperty.RegisterAttached(
        "DataGridColumnSettings",
        typeof(DataGridColumnSettings),
        typeof(DataGridColumn));
    private static void SetDataGridColumnSettings(DataGridColumn column, DataGridColumnSettings settings) { column.SetValue(DataGridColumnSettingsProperty, settings); }
    private static DataGridColumnSettings GetDataGridColumnSettings(DataGridColumn column) { return column.GetValue(DataGridColumnSettingsProperty) as DataGridColumnSettings; }

    public static readonly DependencyProperty DisplayColumnsProperty = DependencyProperty.RegisterAttached(
        "DisplayColumns",
        typeof(IList),
        typeof(DataGridColumns),
        new PropertyMetadata(null, DisplayColumnsPropertyChanged));

    public static void SetDisplayColumns(DataGrid dataGrid, IList columns) { dataGrid.SetValue(DisplayColumnsProperty, columns); }
    public static IList GetDisplayColumns(DataGrid dataGrid) { return dataGrid.GetValue(DisplayColumnsProperty) as IList; }
    private static void DisplayColumnsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var target = d as DataGrid;
        var columns = e.NewValue as IList;
        var template = GetColumnSettingsTemplate(target);

        CreateColumns(target, columns, template);
    }

    public static readonly DependencyProperty ColumnSettingsTemplateProperty = DependencyProperty.RegisterAttached(
        "ColumnSetupTemplate",
        typeof(DataTemplate),
        typeof(DataGridColumns),
        new PropertyMetadata(null, ColumnSettingsTemplateChanged));
    public static void SetColumnSettingsTemplate(DataGrid dataGrid, DataTemplate columnSetupTemplate) { dataGrid.SetValue(ColumnSettingsTemplateProperty, columnSetupTemplate); }
    public static DataTemplate GetColumnSettingsTemplate(DataGrid dataGrid) { return dataGrid.GetValue(ColumnSettingsTemplateProperty) as DataTemplate; }
    private static void ColumnSettingsTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var target = d as DataGrid;
        var columns = GetDisplayColumns(target);
        var template = e.NewValue as DataTemplate;

        CreateColumns(target, columns, template);
    }

    private static void CreateColumns(DataGrid dataGrid, IList columnViewModels, DataTemplate columnSettings)
    {
        if (dataGrid == null)
            return;
        dataGrid.Columns.Clear();

        if (columnViewModels == null)
            return;

        foreach (var column in columnViewModels)
        {
            var newColumn = new DataGridTextColumn();
            newColumn.SetValue(FrameworkElement.DataContextProperty, column);
            if (columnSettings != null)
            {
                var settings = columnSettings.LoadContent() as DataGridColumnSettings;
                if (settings != null)
                {
                    settings.Setup(newColumn, column);
                    SetDataGridColumnSettings(newColumn, settings);
                }
            }
            dataGrid.Columns.Add(newColumn);
        }
    }
}

public class DataGridColumnSettings : FrameworkElement
{
    public static readonly DependencyProperty ColumnBindingPathProperty = DependencyProperty.Register(
        "ColumnBindingPath",
        typeof(string),
        typeof(DataGridColumnSettings),
        new PropertyMetadata(null, ColumnBindingPathChanged));
    public string ColumnBindingPath
    {
        get { return GetValue(ColumnBindingPathProperty) as string; }
        set { SetValue(ColumnBindingPathProperty, value); }
    }
    private static void ColumnBindingPathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var target = d as DataGridColumnSettings;
        if (target == null)
            return;
        target.column.Binding = new Binding(e.NewValue as string);
    }

    public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(
        "Header",
        typeof(object),
        typeof(DataGridColumnSettings));
    public object Header
    {
        get { return GetValue(HeaderProperty); }
        set { SetValue(HeaderProperty, value); }
    }

    private DataGridTextColumn column;
    private object viewModel;

    public void Setup(DataGridTextColumn column, object columnViewModel)
    {
        this.column = column;
        viewModel = columnViewModel;
        this.DataContext = columnViewModel;

        if (Header is FrameworkElement)
        {
            (Header as FrameworkElement).DataContext = columnViewModel;
            column.Header = Header;
        }
        else
            BindingOperations.SetBinding(column, DataGridColumn.HeaderProperty, new Binding("Header") { Source = this });
        column.Binding = new Binding(ColumnBindingPath);
    }
}

和我的XAML代码:

<DataGrid t:DataGridColumns.DisplayColumns="{Binding Columns}" ItemsSource="{Binding Rows}" AutoGenerateColumns="False">
    <t:DataGridColumns.ColumnSettingsTemplate>
        <DataTemplate>
            <t:DataGridColumnSettings ColumnBindingPath="{Binding BindingPropName}">
                <t:DataGridColumnSettings.Header>
                        <TextBlock Text="{Binding Header}"/>
                </t:DataGridColumnSettings.Header>
            </t:DataGridColumnSettings>
        </DataTemplate>
    </t:DataGridColumns.ColumnSettingsTemplate>
</DataGrid>

我想要实现的一切都是添加CellTemplate:

<DataGrid t:DataGridColumns.DisplayColumns="{Binding Columns}" ItemsSource="{Binding Rows}" AutoGenerateColumns="False">
    <t:DataGridColumns.ColumnSettingsTemplate>
        <DataTemplate>
            <t:DataGridColumnSettings ColumnBindingPath="{Binding BindingPropName}">
            <t:DataGridColumnSettings.Header>
                <TextBlock Text="{Binding Header}"/>
            </t:DataGridColumnSettings.Header>
            <t:DataGridColumnSettings.CellTemplate>
                <TextBlock Text="{Binding ColumnBindingPath}"/>
            </t:DataGridColumnSettings.CellTemplate> 
            </t:DataGridColumnSettings>
        </DataTemplate>
    </t:DataGridColumns.ColumnSettingsTemplate>
</DataGrid>

我认为最简单的方法是添加一个依赖属性来获取单元格模板。然后如果存在,在填充DataGrid时创建DataGridTemplateColumn而不是DataGridTextColumn,但是我将CellTemplate TextBlock绑定到ColumnBindingPath依赖项属性时遇到一些问题。请帮忙......

1 个答案:

答案 0 :(得分:0)

绑定到附加属性的语法是:

<TextBlock Text="{Binding Path=(t.DataGridColumns.ColumnBindingPath)}"/>

绑定到附加属性时,需要显式写入Path=。这已在WPF 4.5中修复,因此编写

可能就足够了
<TextBlock Text="{Binding (t.DataGridColumns.ColumnBindingPath)}"/>

请注意,您仍需要在该属性周围使用括号。这是否已经回答了你的问题?