【问题标题】:Change Text Color of DataGrid Cell when value of bound property changes绑定属性值更改时更改 DataGrid 单元格的文本颜色
【发布时间】:2016-01-12 06:43:22
【问题描述】:

我在 WPF 中有一个 DataGrid,其中填充了 ObservableCollection 的元素(ElementGroup 具有 ID 和 Text 属性并从 XML 文件中读取的项目)。 我想要实现的是,当用户编辑单元格的值时,单元格内容的文本颜色会发生变化。一旦用户离开单元格并且值与原始值不同,单元格的颜色应保持例如绿色。

我目前所拥有的:

具有以下数据网格的用户控件:

<DataGrid Grid.Row="7" Grid.Column="3" ItemsSource="{Binding Config.ElementGroups, Mode=TwoWay}" AutoGenerateColumns="False" >            
    <DataGrid.Columns>  
        <DataGridTextColumn Header="ID" Binding="{Binding Id, Mode=TwoWay}" Width="Auto"/>
        <DataGridTextColumn Header="Group Name" Binding="{Binding Text, Mode=TwoWay}" Width="*" />
    </DataGrid.Columns>
</DataGrid>

用户控件后面的代码中没有任何内容。

具有 2 个属性的 ElementGroup 类,它还实现了INotifyPropertyChanged(额外的类以便重用它)

public class ElementGroup : NotifyPropertyChangedBase, ITag
{
    private int myId;
    private string myText;

    public ElementGroup()
    {
        Elements = new List<Element>();
    }

    public List<Element> Elements { get; private set; }

    public int Id 
    { 
        get { return myId; }
        set
        {
            if (myId == value)
            {
                return;
            }
            myId = value;
            OnPropertyChanged();
        }
    }

    public string Text
    {
        get { return myText; }
        set
        {
            if (myText == value)
            {
                return;
            }
            myText = value;
            OnPropertyChanged();
        }
    }
}

数据网格行已正确填充:

datagrid example

我在我的视图模型中监听属性更改事件。当我将它设置为处理程序然后更改数据网格的一个单元格时,该事件被触发并且断点被击中。 HasTextChangedHasIdChanged 函数在更改是真实更改时返回 true,如果值更改为之前的值,则返回 false。

private void GroupPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
{
    ElementGroup changedGroup = sender as ElementGroup;

    switch (propertyChangedEventArgs.PropertyName)
    {
        case "Text":
            GroupChanged = HasTextChanged(changedGroup);
            OnPropertyChanged("GroupChanged");
            break;
        case "Id":
            GroupChanged = HasIdChanged(changedGroup);
            OnPropertyChanged("GroupChanged");
            break;
    }           
}

我尝试过的:

起初我以为我只是返回一个颜色并将前景色绑定到数据网格,就像它适用于简单的TextBox

<TextBox Grid.Row="5" Grid.Column="3" Text="{Binding Config.Description}" Foreground="{Binding DescriptionColor}"/>

但是将相同的前台绑定到DataGridTextColumns 不起作用。我尝试调整此处找到的答案 (Change Color of DatagridCell) 但无法使其正常工作(以下示例中的DescriptionColorSolidColorBrush DescriptionColor = Brushes.Green

<DataGridTextColumn Header="Group Name" Binding="{Binding Text, Mode=TwoWay}" Width="*" >
    <DataGridTextColumn.CellStyle>
        <Style>
            <Setter Property="Border.Background" Value="{Binding DescriptionColor}"/>
        </Style>
    </DataGridTextColumn.CellStyle>
</DataGridTextColumn>

我发现的所有其他单元格颜色更改答案都是关于设置触发器,如果​​值更改为指定值,则可以更改颜色。

所以我决定采用“真正改变是/否”的方法,并添加了一个样式触发器我的数据网格:

<DataGrid Grid.Row="7" Grid.Column="3" ItemsSource="{Binding Config.ElementGroups, Mode=TwoWay}" AutoGenerateColumns="False" >
    <DataGrid.CellStyle>
        <Style TargetType="{x:Type DataGridCell}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding GroupChanged}" Value="True">
                    <Setter Property="Background" Value="Green"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding GroupChanged}" Value="False">
                    <Setter Property="Background" Value="Black"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </DataGrid.CellStyle>
    <DataGrid.Columns>  
        <DataGridTextColumn Header="ID" Binding="{Binding Id, Mode=TwoWay}" Width="Auto"/>
        <DataGridTextColumn Header="Group Name" Binding="{Binding Text, Mode=TwoWay}" Width="*" />
    </DataGrid.Columns>
</DataGrid>

这也不起作用,我开始怀疑我是否错过了一些基本的东西。

有没有人知道我做错了什么,或者我必须做什么才能让它发挥作用? 我必须承认,我并不是 100% 了解触发器的工作原理以及它是否真的知道该做什么......

谢谢

【问题讨论】:

    标签: c# wpf xaml mvvm datagrid


    【解决方案1】:

    如果我清楚地了解您想标记用户当前正在编辑的单元格。所以如果你使用DataGridTextBoxColumns,你可以为他们添加EditingElementStyle

    <DataGrid.Resources>
        <Style x:Key="EditingStyle" TargetType="TextBox">
            <Setter Property="Background" Value="Green" />
            <Setter Property="Foreground" Value="White" />
        </Style>
    </DataGrid.Resources>
    

    列应该是这样的。

    <DataGridTextColumn Header="ID" Binding="{Binding Id, Mode=TwoWay}" Width="Auto"
                        EditingElementStyle="{StaticResource EditingStyle}" />
    

    更新

    要保留已编辑单元格的颜色,您可以 1 添加一些 bool 属性到 ElementGroup 中,表示已编辑单元格。像这样。

    private bool _isIdChanged;
    public bool IsIdChanged
    {
        get { return _isIdChanged; }
        set { _isIdChanged = value; NotifyPropertyChanged( "IsIdChanged" ); }
    }
    

    2 您应该在 id setter 中添加 IsIdChanged = true

    ...
    myId = value;
    OnPropertyChanged();
    IsIdChanged = true;
    

    3 更改ID 列的绑定。

    Binding="{Binding Id, Mode=TwoWay, NotifyOnTargetUpdated=True}"
    

    4 为该列添加样式。

    <Style x:Key="IdStyle" TargetType="DataGridCell">
        <Style.Triggers>
            <DataTrigger Binding="{Binding IsIdChanged}" Value="True">
                <Setter Property="Background" Value="Green" />
            </DataTrigger>
        </Style.Triggers>
    </Style>
    
    <DataGridTextColumn Name="ID" ... CellStyle="{StaticResource IdStyle}" />
    

    5 绑定到DataGrid 后,应将集合元素的IsIdChanged 的所有值更改为false。并且它需要在从后面的代码中更改值后将其设置为 false。

    6 应该为其他列添加相同的代码。希望这会有所帮助。

    更新

    我查看了您的代码,您应该将 DataTrigger 绑定更改为此。

    <DataTrigger Binding="{Binding IdChanged}" Value="True">
        <Setter Property="Background" Value="Green" />
    </DataTrigger>
    

    您应该在ChangeConfigSettingViewModel 的构造函数中添加这些字符串。它应该是用于将 IdChanged 值初始化为 false 的构造函数的最后一个字符串。

    foreach ( PersonModel pers in myPersons )
    {
        pers.IdChanged = false;
    }
    

    【讨论】:

    • 有趣,但这不是我想要实现的。也许我不够清楚。我不想在编辑过程中改变颜色,但是当值被编辑并且用户点击其他地方时,颜色应该保持不变。
    • 感谢您的努力。不幸的是,这对我也不起作用。我看到属性已更改并且值设置为“true”,但颜色不会更改......就像信息没有通过数据网格一样。也许我的代码有一些基本错误......我想我会创建一个新项目,看看如果我只有这个数据网格它是否有效。
    • 您可以将Style中的DataTrigger更改为Binding={Binding Id} Value="5"并将DataGrid中的id更改为5,只是为了测试添加样式到列的正确性。在我的测试示例中它工作正常,可能OnPropertyChanged() 函数存在一些问题。
    • 我试过了,但还是这样。没有颜色变化。我已更改 ElementGroup 项目的 PropertyChanged 事件的事件处理程序,只在 MessageBox 中向我显示已更改属性的名称:当我编辑数据网格单元格时,我得到了 Id 或 Text 更改的正确信息。但我没有收到新的IsIdChanged 属性的消息框。不幸的是,绑定 id 并将数字设置为值也不起作用:(我不知道,但我一定错过了一些基本的东西......
    • 您能否为您的代码提供这些更新?也许我会看到一些我们错过的东西。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-29
    • 2021-04-06
    • 2019-02-16
    • 2015-12-16
    • 2017-08-07
    相关资源
    最近更新 更多