首页 文章

WPF DataGrid的结构 - 根据值更改单元格

提问于
浏览
3

我确实将一个Object绑定到 DataGridTextColumn ,并想在相应的CellStyle中引用其中一个属性 . 我假设此列的每个单元格都包含 MyObject 的实例 . 但是我无法在 DataGridCell 中找到对象的引用(我使用了一个简单的转换器来设置断点并搜索了 DataGridCell -object很长一段时间) .

我正在寻找属性MyObject.IsEnabled,并希望在路径属性中引用它与???在下面的代码中 . 有什么建议?

<DataGridTextColumn Binding="{Binding MyObject}">
    <DataGridTextColumn.CellStyle>
        <Style TargetType="DataGridCell">
            <Style.Triggers>
                <DataTrigger Path="???" Binding="{Binding RelativeSource={RelativeSource Self}, PresentationTraceSources.TraceLevel=High,Converter={StaticResource debugger}}"  Value="False">
                    <!-- some setters -->
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </DataGridTextColumn.CellStyle>
</DataGridTextColumn>

EDIT:

由于我希望稍后将此样式应用于我的DataGrid的所有单元格,因此必须通过 RelativeSource 找到绑定到单元格的对象,而不是向 MyObject 添加硬编码绑定 .

SOLUTION

由于antiocol的输入,我能够为我的案例找到一个可能适用于类似问题的解决方案 .

由于问题是我们无法访问 CellStyle 中的Cell或 CellModel 的值,因此我们使用 DataGridCell 上的附加属性将整个 CellModel 存储在那里 . 从那里我们可以将 DataGridCell 的任何可访问属性绑定到 CellModel 的任何属性 .

code for attached property:

public static class DataGridUtils
{
public static CellModel GetCellModel(DependencyObject obj)
{
    return (CellModel)obj.GetValue(CellModelProperty);
}
public static void SetCellModel(DependencyObject obj, CellModel value)
{
    obj.SetValue(CellModelProperty, value);
}
public static readonly DependencyProperty CellModelProperty =
    DependencyProperty.RegisterAttached("CellModel", typeof(CellModel), typeof(DataGridUtils), new UIPropertyMetadata(null));

我们需要在DataGrid中的每个单元格上设置此属性 . 我没有在XAML中找到一个很好的解决方案,所以现在我在检索信息之前将它设置在转换器中 . (赞赏的改进建议)

Converter:

public class CellToEnabledConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        var cell = values[0] as DataGridCell;
        DataGridTextColumn column = cell.Column as DataGridTextColumn;
        //you should probably check if column is null after casting.
        Binding b = column.Binding as Binding;

        //Any suggestions on how to create a Binding to the parent object properly? 
        //I needed this workaround since I bind `MyObject.Value` to the `DataGridTextColumn`, 
        //but need a reference to `MyObject` here.
        Binding b1 = new Binding(b.Path.Path.Split('.')[0]){ Source = cell.DataContext };

        cell.SetBinding(DataGridUtils.CellModelProperty, b1);
        CellModel c = DataGridUtils.GetCellModel(cell);

        return c.IsEnabled;
    }

现在我们可以在XAML中定义全局 Style 并将其应用于整个 DataGrid 而不是单个列 .

<Window.Resources>
    <converter:CellToEnabledConverter x:Key="CellToEnabledConverter" />

    <Style x:Key="DataGridCellStyle" TargetType="DataGridCell">
        <Style.Triggers>
            <DataTrigger Value="False">
                <DataTrigger.Binding>
                    <!--This Converter works only on DataGridTextColumns with this minimal example!-->
                    <Binding Converter="{StaticResource CellToEnabledConverter}">
                        <Binding RelativeSource="{RelativeSource Self}" />
                    </Binding>
                </DataTrigger.Binding>
                <!--Setters-->
            </DataTrigger>
        </Style.Triggers>
    </Style>
</Window.Resources>

<DataGrid CellStyle="{StaticResource DataGridCellStyle}">
    <DataGridTextColumn Binding="{Binding MyObject.Value}"/>
</DataGrid>

由于我在网上发现了一些评论,称“使用当前的 DataGrid 无法根据其值设置单元格样式”,我希望这种解决方法可以帮助某人 .

3 回答

  • 1

    我一直在为你的问题尝试另一种解决方案 .

    <Style x:Key="DataGridCellStyle" TargetType="{x:Type DataGridCell}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding Path=., RelativeSource={RelativeSource Self},  Converter={StaticResource DataGridCellToBooleanConverter}, ConverterParameter=IsEnabled}" Value="True">
                <Setter Property="Background" Value="Yellow"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
    
    <DataGrid CellStyle="{StaticResource DataGridCellStyle}">
       <DataGrid.Columns>
            <DataGridTextColumn Header="MyObject1" Binding="{Binding MyObject1}" />
            <DataGridTextColumn Header="MyObject2" Binding="{Binding MyObject2}" />
       </DataGrid.Columns>
    </DataGrid>
    

    另一方面,我假设 DataGridItemsSourceElement 对象的集合(当然还有类似的东西)

    public class Element
    {
        public string Name { get; set; }
        public MyObject MyObject1 { get; set; }
        public MyObject MyObject2 { get; set; }
    }
    public class MyObject
    {
        public string Name { get; set; }
        public bool IsEnabled { get; set; }
        public override string ToString()
        {
            return Name;
        }
    }
    

    最后,转换器:

    public class DataGridCellToBooleanConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            string propertyToAppend = parameter as string;
            var cell = value as DataGridCell;
            var column = cell.Column as DataGridTextColumn;
            Binding b = column.Binding as Binding;
            Binding b1 = new Binding(string.Join(".", b.Path.Path, propertyToAppend)) { Source = cell.DataContext };
            CheckBox dummy = new CheckBox();
            dummy.SetBinding(CheckBox.IsCheckedProperty, b1);
            return dummy.IsChecked;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    

    棘手的部分是使用 ConverterParameter 以传递要在 DataTrigger 中绑定的属性的名称 .

    附:您可以使用反射而不是hacky CheckBox dummy 元素,但这对我有用 .

    希望这可以帮助

  • -1

    我唯一能想到的是将每个 DataGridTextColumn 切换到 DataGridTemplateColumn 并在每个 CellTemplate 内添加一些ContentControl,其DataContext绑定到该列中的属性 .

    这样你就可以为ContentControl创建一个可重用的样式,因为 DataGridCell 对你没有任何帮助:P

    <Style x:Key="MyObjectStyle" TargetType="{x:Type ContentControl}">
        <Setter Property="ContentTemplate">
            <Setter.Value>
                <DataTemplate>
                    <!-- your TextBlock and stuff -->
                </DataTemplate>
            </Setter.Value>
        </Setter>
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsEnabled, PresentationTraceSources.TraceLevel=High, Converter={StaticResource debugger}}"  Value="False">
                    <!-- some setters -->
                </DataTrigger>
            </Style.Triggers>
    </Style>
    
    <DataGridTemplateColumn>
        <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <ContentControl Content="{Binding MyObject}"
                                Style="{StaticResource MyObjectStyle}" />
            </DataTemplate>
        </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>
    
  • 0

    你必须首先修复DataTrigger的sintax,如下所示:

    <DataGridTextColumn Binding="{Binding MyObject}">
        <DataGridTextColumn.CellStyle>
            <Style TargetType="DataGridCell">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding MyObject.IsEnabled, PresentationTraceSources.TraceLevel=High, Converter={StaticResource debugger}}"  Value="False">
                        <!-- some setters -->
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </DataGridTextColumn.CellStyle>
    </DataGridTextColumn>
    

    注意DataTrigger的Binding属性 . 因为 IsEnabled 中的 DataContext 将是 MyObject 对象的实例,所以在该属性中你必须编写 Path ,在你的情况下 IsEnabled . 您不需要使用 RelativeSource ,因为您的 Binding 指向 MyObject ,如前所述 .

    如果要将此样式创建为资源,可以执行以下操作:

    <Style x:Key="cellStyle" TargetType="DataGridCell">
        <Style.Triggers>
            <DataTrigger Binding="{Binding Path=MyObject.IsEnabled, PresentationTraceSources.TraceLevel=High, Converter={StaticResource debugger}}"  Value="False">
                <!-- some setters -->
            </DataTrigger>
        </Style.Triggers>
    </Style>
    

相关问题