2

使用 WPF DataGrid,我需要根据单元格对象属性的相关值更改 DataGridCell 的各种显示和相关属性,例如 Foreground、FontStyle、IsEnabled 等。

现在这在代码中很容易做到,例如(使用 ObservableDictionaries 的 Observable 集合):

  var b = new Binding("IsLocked") { Source = row[column], Converter = new BoolToFontStyleConverter() };
  cell.SetBinding(Control.FontStyleProperty, b);

并且工作正常,但是我看不到如何在 XAML 中执行此操作,因为我找不到将路径设置为单元格对象属性的方法。

一种 XAML 尝试是:

<Setter Property="FontStyle">
    <Setter.Value>
        <MultiBinding Converter="{StaticResource IsLockedToFontStyleConverter}" Mode="OneWay" UpdateSourceTrigger="PropertyChanged">
              <Binding />
              <Binding RelativeSource="{x:Static RelativeSource.Self}"/>
        </MultiBinding>
    </Setter.Value>
</Setter>

但没有绑定到IsLocked属性

public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
    var row = (RowViewModel) values[0];
    var cell = (DataGridCell) values[1];
    if (cell != null && row != null)
    {
        var column = DataGridMethods.GetColumn(cell);
        return row[column].IsLocked ? "Italic" : "Normal";
    }

    return DependencyProperty.UnsetValue;
}

请注意,以前的版本返回row[col].IsLocked并使用 DataTrigger 设置 FontStyle,但返回的对象不是数据绑定的。

当然,请注意,应用程序在设计时不知道列是什么。

最后,DataTable 对我的要求来说效率太低了,但我很想看看如何用 DataTables 来完成,如果有这样的解决方案,这可能在其他地方有用(尽管我更喜欢使用集合)。

当然这是一个常见问题,我是一个 WPF 新手,试图在我的项目中使用所有 MVVM,但是这个问题阻碍了我使用 WPF DataGrid。

4

1 回答 1

4

那么这是我找到的最简单的解决方案。(实际上我在发布这个和另一个问题之前就已经有了它,但对这样的解决方案感到尴尬。因为在这里没有听到任何其他信息,只是以防万一其他人面临同样的问题,我想我会分享它。)

在 DataGridCell Tag 属性中放置对单元格对象的引用。我结合使用 XAML 和转换器内部的代码绑定来执行此操作,如下所示:

   <Setter Property="Tag">
       <Setter.Value>
           <MultiBinding Converter="{StaticResource CellViewModelToTagConverter}" Mode="OneWay" UpdateSourceTrigger="PropertyChanged">
              <Binding />
              <Binding RelativeSource="{x:Static RelativeSource.Self}"/>
          </MultiBinding>
       </Setter.Value>
   </Setter>

 public class CellViewModelToTagConverter : IMultiValueConverter
 {
     public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
     {
        var row = values[0] as RowViewModel;
        var cell = values[1] as DataGridCell;
        if (row != null && cell != null)
        {
            var column = DataGridMethods.GetColumn(cell);
            // hack within hack!!! (using tag way is itself a hack?)
            var b = new Binding("Self") {Source = row[column]};
            cell.SetBinding(FrameworkElement.TagProperty, b);
            //...
            //return row[column];
            return DependencyProperty.UnsetValue;
        }
        return DependencyProperty.UnsetValue;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

您可以通过我在转换器中的注释来判断我对这个解决方案的看法。(我必须向 Cell 对象添加一个 Self 属性并在构造函数中设置 Self=this)。

它仍然使我的 Datagrid 编码完全是 MVVM - 如果您接受我在转换器内部所做的与 MVVM 一致。无论如何它有效!

因此,这样做我可以查看和管理来自 XAML 的所有内容,例如通过将 XAML 放置在相关列单元格样式中(不是通过 DataGrid.CellStyle 执行此操作),仅在某些列上控制此类绑定。

无论如何,一个使用示例是

<Style.Triggers>
      <DataTrigger Value="true" Binding="{Binding RelativeSource={RelativeSource Self}, Path=Tag.IsLocked}">
            <Setter Property="FontStyle" Value="Italic"/>
            <Setter Property="IsEnabled" Value="False"/>
       </DataTrigger>
 </Style.Triggers>

在 XAML 级别上,它既简单又优雅(特别是对于我大量使用单元对象属性的各种工具提示和弹出窗口)。但是我确信有更好的方法可以做到这一点,是吗?

希望当我可以使用 Net 4.0 和动态对象时,这一切都会消失,但对于这个项目,我不能。

于 2010-09-05T11:11:22.937 回答