DataGridColumn在代码中绑定

时间:2010-08-08 20:24:13

标签: wpf silverlight data-binding datagrid

有谁知道如何在代码中执行等效的XAML绑定?

<DataGrid ... >
    <DataGrid.Columns>
        <DataGridTextColumn 
            Binding="{Binding Description}"  <=== set in code **
        />
    </DataGrid.Columns>
</DataGrid>

干杯,
Berryl

===更新====

看起来我一直在寻找的方法是DataGridColumn.GenerateElement

如果是这样,那么现在问题的重点是如何正确设置Binding。我想做这个代码的原因是我的网格有7列在视觉上相同,其数据可以通过索引知道。

所以我希望能够通过使用具有索引属性的子类DataGridTextColumn来简化xaml,并且只需:

<DataGrid ... >
    <DataGrid.Columns >
        <local:DayOfWeekColumn Index="0" />
        <local:DayOfWeekColumn Index="1" />
        ....
        <local:DayOfWeekColumn Index="7" />
    </DataGrid.Columns >
</DataGrid >

===经过修改的问题===

假设Binding本身在逻辑上和语法上都是正确的,那么BindingOperations.SetBinding的参数应该是什么?

    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem) {
        var activity = (ActivityViewModel)dataItem;
        var cellData = activity.Allocations[Index];
        var b = new Binding
                {
                    Source = cellData,
                    UpdateSourceTrigger = UpdateSourceTrigger.LostFocus,
                    Converter = new AllocationAmountConverter()
                };


        BindingOperations.SetBinding(??, ??, b);
        return ??;
    }

=== ARAN的编辑=====

我现在没有覆盖GenerateElement,而是试图获取一个静态帮助器来为我设置绑定。在任何情况下都需要帮助程序来补偿无法在当前MSFT的DataGrid实现中绑定Header内容。

基本上,我们的想法是从网格中捕获DC并在每个列上根据需要使用它,在这种情况下,它将是Header内容,单元格样式和Binding。这是代码:

public class TimesheetDataGridColumnContextHelper
{

    static TimesheetDataGridColumnContextHelper() {
        FrameworkElement.DataContextProperty.AddOwner(typeof (DataGridTextColumn));
        FrameworkElement.DataContextProperty.OverrideMetadata(
            typeof (DataGrid), 
            new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, OnDataContextChanged));
    }

    public static void OnDataContextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var grid = d as DataGrid;
        if (grid == null || !grid.Name.Equals("adminActivityGrid")) return;

        foreach (var col in grid.Columns) {

            var dowCol = col as DayOfTheWeekColumn;
            if (dowCol == null) continue;

            var context = (IActivityCollectionViewModelBase) e.NewValue;
            var index = Convert.ToInt32(dowCol.DowIndex);

            _setHeader(dowCol, context, index);

            var editStyle = (Style) grid.FindResource("GridCellDataEntryStyle");
            dowCol.CellStyle = editStyle;

            _setBinding(dowCol, index, context);

        }
    }

    private static void _setBinding(DayOfTheWeekColumn dowCol, int index, IActivityCollectionViewModelBase context) {
        dowCol.Binding = new Binding
                         {
                             Path = new PropertyPath(string.Format("Allocations[{0}]", index)),
                             UpdateSourceTrigger = UpdateSourceTrigger.LostFocus,
                             Converter = new AllocationAmountConverter()
                         };
    }

    private static void _setHeader(DataGridColumn col, IActivityCollectionViewModelBase context, int index)
    {
        var date = context.HeaderDates[index];
        var tb = new TextBlock
                 {
                     Text = date.ToString(Strings.ShortDayOfWeekFormat),
                     ToolTip = date.ToLongDateString()
                 };
        col.Header = tb;
    }

}

}

除了 Binding之外,

所有内容都。我不知道是不是因为我的绑定在某种程度上是错误的(虽然我没有明显的错误)或者这不是一个设置它的好地方。我运行时,网格列只是空的。

任何想法??

干杯,
Berryl

===固定! ===

上次更新中的逻辑实际上是正确的,但是在DataGrid的内部丢失我错过了我的Binding.Path缺少要绑定的属性!感谢Aran理解这个问题,意识到GenerateElement覆盖不是必需的,并且认识到不应该设置Binding Source。

2 个答案:

答案 0 :(得分:5)

你总是在做那些令人费解的网格位...... Beryl?

做一些事情。使用reflector查看DataGridTextColumn中GenerateElement的实现。 (.NET程序员住在反射器中)

现在回答:

在datagrid中,每列不是可视树的一部分。该列有两个方法GenerateElement和GenerateEditingElement。这些方法分别返回单元格的查看器和编辑器。在上面的方法中,您不是在创建查看器,它可能是一个TextBlock。

来自反射器,GenerateElement的实现如下,注意他们做的第一件事是为单元创建查看器。

protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
{
    TextBlock e = new TextBlock();
    this.SyncProperties(e);
    base.ApplyStyle(false, false, e);
    base.ApplyBinding(e, TextBlock.TextProperty);
    return e;
}

有了文本块后,您可以使用下面的行来设置文本块。

BindingOperations.SetBinding(textBlock, TextBlock.TextProperty, binding);

但我并不确信您确实需要覆盖GenerateElement和GenerateEditingElement以获得所需的效果。我认为你可以覆盖基类的Binding属性,只要在设置时用你的额外字段修改那里的绑定。这将意味着其他一切都将正常工作,您不会最终删除列中的功能。再次通过反射器查看类DataGridBoundColumn(抽象基类)将是有益的。

每当设置绑定时,我在其中一个列中执行类似的操作我通过添加额外的属性来修改剪贴板绑定,以便我可以有效地复制和粘贴。

编辑:更新......这应该是另一个问题但是......

您在setBinding方法中明确设置绑定源。在网格中,绑定的源是行中包含的数据。您正在设置它,这意味着每行都是相同的。在设置数据上下文之前,您可以在没有source属性的情况下应用这些时髦的绑定,源成为每行中的项,并且您的绑定应该反映每行中保存的属性的索引。

答案 1 :(得分:0)

基于MSDN,听起来像SetBinding()的第一个参数应该是你想在这种情况下显示绑定的控件(this,假设{{1} }}是GenerateElement()类的成员,第二个属性是绑定数据的属性。我没有非常使用WPF DayOfWeekColumn,但我没有看到任何类似文本属性的设置。

我确实看到DataGrid确实有DataGridTextColumn属性。也许它可以将它设置为您在上面手动创建的绑定?