WPF DataGrid 在编辑后更新单元格样式

3
在XAML中,我有一个在DataGrid中定义为如下的列:
<DataGridTextColumn Header="Name" Binding="{Binding Name}">
    <DataGridTextColumn.CellStyle>
        <Style TargetType="DataGridCell" BasedOn="{StaticResource
               {x:Type DataGridCell}}" >
            <Setter Property="Background" Value="{Binding
                    Converter={StaticResource NameToBrushConverter}}"/>
        </Style>
    </DataGridTextColumn.CellStyle>
</DataGridTextColumn>
NameToBrushConverter会在Name列和FirstName列的内容相同时返回一种颜色,否则它将返回DependencyProperty.UnsetValue
我的问题是,如果我编辑一个单元格并结束编辑,样式不会更新。只有当新输入的值移动到另一行(由于排序)时,背景的有条件着色才会应用。但是,如果编辑后的对象显示在DataGrid的同一行中,则背景颜色不会更新,直到我点击排序为止。只要该单元格移动到另一行,背景就会根据转换器值进行更新。
为此对象实现INotifyPropertyChanged是没有帮助的。
有没有一种方法告诉GridView在编辑单元格后重新评估样式?
dataGrid.Items.Refresh();

调用刷新函数可以解决问题,但是哪个事件是触发刷新的正确事件呢?我尝试在CellEditEnding中使用它,但是出现了一个异常:Refresh不允许在AddNew-EditItem事务中使用。

1个回答

3
  1. 您需要将UpdateSourceTrigger设置为PropertyChanged,因为在DataGrid中,默认设置为LostFocus

  2. 我猜您没有CellEditTemplate

  3. 这是所有问题中最大的问题:您必须在相关转换器上使用多绑定属性。现在它能工作的唯一原因是当失去焦点时,当前单元格中的绑定会刷新并获取您的项 (即绑定或绑定到Path=,将其传递给转换器并输出某些颜色。

编辑:

我现在知道我把UpdateSourceTrigger放在了错误的绑定上。请将其放在上面的Name上,还要在您的单元格样式中绑定到Name

XAML:

 <DataGrid>
    <DataGrid.Columns>
        <DataGridTextColumn Header="Name" Binding="{Binding Name,
                            UpdateSourceTrigger=PropertyChanged}">
            <DataGridTextColumn.CellStyle>
                <Style TargetType="DataGridCell"
                       BasedOn="{StaticResource {x:Type DataGridCell}}" >
                    <Setter Property="Background" Value="{Binding Name,
                            Converter={StaticResource
                            NameToBrushConverter}}"/>
                </Style>
            </DataGridTextColumn.CellStyle>
        </DataGridTextColumn>
    </DataGrid.Columns>
</DataGrid> 

此外,针对您下面的问题,行之间部分移动时仅能工作的唯一原因是因为每个嵌套在 DataGrid 中的绑定的默认 UpdateSourceTriggerLostFocus

当使用以下方法绑定到当前的 DataContext

<SomeElement Tag={Binding}/>

或者:

<SomeElement Tag={Binding Path=.}/>

您没有绑定到属性。当以下情况发生时,Binding将被评估:

  1. DependencyObject初始化并且所有DP都被评估。它第一次获取它的值。

  2. UpdateSourceTrigger=LostFocus(在DataGrid中默认)会在LostFocus事件上触发。这就是为什么在行之间切换时会评估您的Binding。

  3. UpdateSourceTrigger=PropertyChanged。如果您希望在DataContext上进行此操作,则必须显式设置一个属性,该属性将返回自身,并在名称属性更改时调用它。

类似于以下内容:

C#:

public class Entity : INotifyPropertyChanged
{
    private string _name;
    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            PropertyChanged(this,
                new PropertyChangedEventArgs("Name"));
            PropertyChanged(this,
                new PropertyChangedEventArgs("Self"));
        }
    }
    private string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set
        {
            _firstName = value;
            PropertyChanged(this,
                new PropertyChangedEventArgs("FirstName"));
            PropertyChanged(this,
                new PropertyChangedEventArgs("Self"));
        }
    }
    public Entity Self { get { return this; } }
    public event PropertyChangedEventHandler PropertyChanged =
        delegate { };
}

XAML:

<Style TargetType="DataGridCell" BasedOn="{StaticResource
       {x:Type DataGridCell}}" >
    <Setter Property="Background" Value="{Binding
            Self,Converter={StaticResource NameToBrushConverter}}"/>
</Style>

但是这段代码不会在失去焦点时计算,但您也不需要它,因为它会在第一次计算,并在名称更改时再次计算。

你的例子可以运行,但我还有一个问题。 - bebo
我改变了转换器的方式,以便我将对象作为参数获取。因此,我只需编写<Binding />,而不是添加Path、Name和FirstName。所以我得到整个对象。只要我添加第二个绑定路径与任何属性(例如<Binding Path="MyProperty" />),字段就会更新。但是当我仅传递对象(仅<Binding />并删除所有其他包含路径的绑定)时,PropertyChangeEvent不会触发样式更新。有没有办法在传递Person对象的情况下使其工作,而不是传递2个字符串? - bebo
你所说的传递对象本身是什么意思?就像我上面所述的绑定对象本身(即Binding),它只会在第一次和每次失去焦点时发生。你看,你没有一个属性可以绑定到,你可以在其上引发属性更改事件。我猜你可以公开一个属性,类似于Self { get return this;}并为其引发属性更改事件。但是当你的FirstName名称更改时,你必须在你的类中这样做,而那将比我的解决方案难以阅读得多。 - eran otzap
1
最后一件事情就是我在寻找的。谢谢。 - bebo
因为您需要在转换器中获取实体吗?我认为这样不太易读。通过查看XAML,您无法确定绑定何时被评估。 - eran otzap

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接