将单元格对象的属性绑定到 WPF DataGrid 中的 DataGridCell

发布于 2024-09-17 10:24:47 字数 1615 浏览 7 评论 0原文

使用 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 中执行此操作,因为我找不到设置 Path 的方法到单元格对象的属性。

一个 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 对于我的要求来说效率太低,但我很想看看 DataTable 是如何完成的,如果有这样的解决方案,这可能在其他地方有用(尽管我更喜欢使用集合)。

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

Using the WPF DataGrid I have the need to change various display and related properties of a DataGridCell - such as Foreground, FontStyle, IsEnabled and so on - based on the relevant value of the cell object property.

Now this is easy to do in code, for example (using an Observable Collection of ObservableDictionaries):

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

and works fine, however I cannot see how to do this in XAML since I can find no way to set Path to a cell object's property.

One XAML attempts is:

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

but there is no binding to the IsLocked property

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;
}

Please note that a previous version returned row[col].IsLocked and set the FontStyle using a DataTrigger but a returned object is not databound.

Note, of course, that the application does not know what the columns are at design time.

Finally DataTable's are far too inefficient for my requirements but I would be interested to see how this is done with DataTables anyway, if there is such a solution for them, this might be useful elsewhere (although I prefer using collections).

Surely this is a common issue and I am a WPF noobie trying to go all MVVM on my project, but this issue is holding me back with respect to using the WPF DataGrid.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

只有一腔孤勇 2024-09-24 10:24:47

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

将对单元格对象的引用放入 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 和动态对象时这一切都会消失,但对于这个项目我不能。

Well here is the simplest solution I have found. (Actually I had it before I posted this and the other question but was embarrased at such a solution.Since have heard nothing else here and just it is in case anyone else is faced with the same problem, I thought I would share it.)

Put a reference to the cell object in the DataGridCell Tag property. I do this with a combination of XAML and a code binding inside a converter as follows:

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

and

 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();
    }
}

You can tell what I think of this solution by my comments inside the converter.(I had to add a Self property to the Cell object and make Self=this in the constructor).

Still it enables my Datagrid coding to be entirely MVVM - if you accept that what I have done inside the converter is consistent with MVVM. Anyway it works!

So doing it this way I can see and manage everything from XAML such as control such binding only on certain columns by placing the XAML within the relevant column cellstyles (that is not doing this via DataGrid.CellStyle).

Anyway, an example of usage is

<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>

On the XAML level it is both simple and IMHO elegant (especially for various ToolTips and Popups for which I make heavy usage of cell object's properties). However I am sure there is a better way of doing this, is there?

Hopefully this all goes away when I can use Net 4.0 and dynamic objects, but for this project I cannot.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文