WPF DataGrid的结构 - 根据值

时间:2015-06-18 08:38:01

标签: c# wpf datagrid

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

我正在寻找属性MyObject.IsEnabled,并希望在下面的代码中用 ??? 注明的Path-Property中引用它。有什么建议吗?

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

修改

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

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

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

附加属性的

代码:

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中找到一个很好的解决方案,所以现在我在检索信息之前将它设置在转换器中。 (改进建议赞赏)

转换器:

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 个答案:

答案 0 :(得分: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>

另一方面,我认为ItemsSource的{​​{1}}是DataGrid个对象的集合(当然还有类似的东西)

Element

最后,转换器:

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中绑定的属性的名称。

P.S。您可以使用反射而不是hacky DataTrigger元素,但这适用于我。

希望这有帮助

答案 1 :(得分:0)

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

通过这种方式,您可以为该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>

答案 2 :(得分:-1)

你必须首先修复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属性。由于每个Path中的IsEnabled将是{{1}的实例,因此您必须在DataContext中编写DataGridCell该属性对象。您不需要使用MyObject,因为您的RelativeSource指向Binding,如前所述。

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

MyObject