当绑定属性的值更改时,更改DataGrid单元格的文本颜色

本文关键字:DataGrid 更改 单元格 文本 颜色 属性 绑定 | 更新日期: 2023-09-27 18:29:51

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

数据网格行已正确填充:

数据网格示例

我在视图模型中收听属性更改事件。当我将事件设置为处理程序,然后更改数据网格的一个单元格时,就会触发事件并命中断点。如果更改为实际更改,则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上并没有起作用。我试图调整这里找到的答案(更改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%理解触发器是如何工作的,如果它真的知道该怎么做…

感谢

当绑定属性的值更改时,更改DataGrid单元格的文本颜色

如果我清楚地理解您想要标记用户当前编辑的单元格。因此,如果您正在使用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}" />

更新

要重新绘制编辑过的单元格的颜色,可以在ElementGroup中添加一些表示编辑过的单元的bool道具。像这样的东西。

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

2您应该将IsIdChanged = true添加到id setter中。

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