2010-08-08 114 views
1

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

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

干杯,
Berryl

=== UPDATE ====

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

如果是这样,那么这个问题的焦点是如何正确设置Binding。我想做这个代码的原因是我的网格有7列在视觉上是完全相同的,并且其数据可以被索引所知。

所以我希望能够通过使用具有索引属性的子类DataGridTextColumn简化XAML,只是有:

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

===经修订的课题===

假设绑定本身在逻辑上和语法上是正确的,参数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 ??; 
    } 

=== EDITS为ARAN =====

我不重写GenerateElement现在,而是试图让一个静态辅助设置我为我结合。在任何情况下都需要帮助程序来补偿无法绑定当前MSFT DataGrid实现中的标题内容。

基本上这个想法是从网格中捕获DC,并根据需要在每个列上使用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; 
    } 

} 

}

一切正常,除了绑定。我不知道是不是因为我的绑定是错误的(尽管我没有明显的错误),或者这不是一个设置它的好地方。当我运行它时,网格列只是空的。

任何想法??

干杯,
Berryl

===修复! ===

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

回答

4

你总是在做错误的网格位呃Beryl?

做几件事。使用reflector来查看DataGridTextColumn中的GenerateElement的实现。 (.NET程序员生活在反射器)

现在的答案:

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

from reflector,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方法绑定的源。在网格中,绑定的来源是包含在该行中的数据。你正在设置它,这意味着每行都是一样的。您可以在设置数据上下文之前应用这些没有源属性的时髦绑定,源将成为每行中的项目,并且绑定应该反映每行中保存的属性的索引。

+0

嗨阿兰。是的,我的小提琴正在为此做一个锻炼,但似乎值得一试。请参阅我上次的编辑(“编辑ARAN”)以获取最新方法。干杯! – Berryl 2010-08-09 21:35:31

+0

明白了。是我的绑定路径中的一个蹩脚的语法错误(应该是“Allocations [{0}]。Amount”)感谢您的帮助! – Berryl 2010-08-11 00:18:40

0

基于MSDN,它听起来像的SetBinding()第一参数应该是要显示在所述结合对照(this在这种情况下,假设GenerateElement()DayOfWeekColumn类的一个成员),并且所述第二属性是将数据绑定到的属性。我还没有使用WPF DataGrid,但我没有看到任何文本属性设置。

虽然我确实看到DataGridTextColumn确实有Binding属性。也许它会将其设置为您在上面手动创建的绑定?

+0

伟大的想法,我的初衷是做到这一点,但它在某种程度上使方法进入一个无限循环。什么是PITA - 感谢您的回复! – Berryl 2010-08-09 00:13:07