【问题标题】:WPF MVVM - Datagrid does not update changed properties of child itemsWPF MVVM - Datagrid 不更新子项的更改属性
【发布时间】:2014-05-15 14:12:47
【问题描述】:

我在 MVVM 应用程序内的 WPF 表单上有一个可编辑的数据网格。

用户可以在此页面上执行两种可能的操作,这些操作会导致其中一行中的某些数据发生更改。其中一个可编辑字段 - 已请求 - 可能会导致另一个属性发生更改,并且有一个样式触发器取决于其值:

public bool OverRequested
{
    get
    {
        if(this.Requested > this.Volume)
        {
            return true;
        }
        return false;
    }
}

在 XAML 中:

<DataGridTextColumn Header="Requested" Binding="{Binding Requested}">
    <DataGridTextColumn.CellStyle>
        <Style TargetType="DataGridCell">
            <Style.Triggers>
                <DataTrigger Binding="{Binding OverRequested}" Value="true">
                    <Setter Property="Foreground" Value="Red"/>
                    <Setter Property="ToolTip" Value="The requested volume is greater than the available volume" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </DataGridTextColumn.CellStyle>
</DataGridTextColumn>

另一个是更新行后面的数据项并更改该项上的值的按钮。

虽然数据网格本身会响应更改 - 如果您从底层 ObservableCollection 添加或删除行,它会在 UI 中相应更新 - 对行下方项目的这些属性的更改不会更新。

我知道这是设计使然,因为 observableCollection 中的项目的更改不会冒泡,并且必须特别注意,但我正在努力找出如何实现我想要的。

我已经尝试过 - 正如其他地方所建议的那样 - 覆盖 ObservableCollection 上 CollectionChanged 的​​事件处理程序,以向其中的项目添加通知警报:

private void ObservableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    if (e.NewItems != null)
    {
        foreach (var item in e.NewItems)
        {
            (item as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
        }
    }
}

但是里面的项目没有实现 INotifyPropertyChanged 接口——它们是实体框架对象而不是 ViewModel。所以演员表失败了。

有什么方法可以实现吗?由于只有两个属性要查看,我很乐意手动进行 - 但即使调用 OnPropertyChanged("") 来更新 ViewModel 中的所有属性也不会导致数据网格内的属性刷新。

【问题讨论】:

    标签: c# wpf mvvm datagrid


    【解决方案1】:

    也许您可以尝试另一种方式,使用转换器。我有一个做类似事情的应用程序。我通常需要一个测试应用程序才能让这些东西恰到好处,但试试这个:

    <DataGridTextColumn Header="Requested" Binding="{Binding Requested}">
    <DataGridTextColumn.CellStyle>
        <Style TargetType="DataGridCell">
             <Setter Property="Foreground">
                  <Setter.Value>
                    <MultiBinding Converter="{StaticResource OverRequestedForegroundMultiConverter}">
                        <Binding Path="Requested" />
                        <Binding Path="Volume" />
                    </MultiBinding>
                  </Setter.Value>
             </Setter>
             <Setter Property="ToolTip">
                  <Setter.Value>
                    <MultiBinding Converter="{StaticResource OverRequestedTooltipMultiConverter}">
                        <Binding Path="Requested" />
                        <Binding Path="Volume" />
                    </MultiBinding>
                  </Setter.Value>
             </Setter>
        </Style>
    </DataGridTextColumn.CellStyle>
    

    转换器看起来像这样:

    public class OverRequestedForegroundMultiConverter : IMultiValueConverter
    {
        #region IValueConverter Members
    
        public object Convert(object[] value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value != null && value.Length == 2)
            {
                if (value[0] is int && value[1] is int)
                {
                    int requested = (int)value[0];
                    int volume = (int)value[1];
                    if (requested > volume)
                        return Colors.Red;
                }
            }
            return Colors.Gray; // Or whatever color you want
        }
    
        public object[] ConvertBack(object value, Type[] targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    
        #endregion
    }
    
        public class OverRequestedTooltipMultiConverter : IMultiValueConverter
        {
            #region IValueConverter Members
    
            public object Convert(object[] value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                if (value != null && value.Length == 2)
                {
                    if (value[0] is int && value[1] is int)
                    {
                        int requested = (int)value[0];
                        int volume = (int)value[1];
                        if (requested > volume)
                            return "The requested volume is greater than the available volume";
                    }
                }
                return null;
            }
    
            public object[] ConvertBack(object value, Type[] targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
    
            #endregion
        }
    

    不要忘记将转换器添加到您的 app.xaml:

    <app:OverRequestedForegroundMultiConverter x:Key="OverRequestedForegroundMultiConverter" />
    <app:OverRequestedTooltipMultiConverter x:Key="OverRequestedTooltipMultiConverter" />
    

    【讨论】:

    • 感谢您,这是一个有趣的方法。它适用于我的 OverRequested 属性,但是当 Booking 属性更新时,类似的方法似乎不会触发。
    • FYI OverRequested 在 DataGrid 编辑后更改,但 Booking 是通过按钮单击命令更改的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-16
    • 1970-01-01
    • 2021-06-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多