WPF MVVM - Datagrid不更新子项的更改属性 [英] WPF MVVM - Datagrid does not update changed properties of child items

查看:192
本文介绍了WPF MVVM - Datagrid不更新子项的更改属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



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

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

而在XAML中:

 < DataGridTextColumn Header =RequestedBinding ={Binding Requested}> 
< DataGridTextColumn.CellStyle>
< Style TargetType =DataGridCell>
< Style.Triggers>
< DataTrigger Binding ={Binding OverRequested}Value =true>
< Setter Property =ForegroundValue =Red/>
< Setter Property =ToolTipValue =请求的卷大于可用卷/>
< / 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(e.NewItems中的var item)
{
(item as INotifyPropertyChanged).PropertyChanged + = new PropertyChangedEventHandler(item_PropertyChanged);
}
}
}

但内部的项目不实现INotifyPropertyChanged接口 - 它们是Entity Framework对象而不是ViewModel。所以演员失败了。



有没有办法实现这个?只有两个属性要观察,我会高兴地手动执行 - 但是即使调用OnPropertyChanged()来更新ViewModel中的所有属性也不会导致数据网格内的内容刷新。

解决方案

也许你可以尝试另一种方式使用转换器。我有一个应用程序做这样的事情。我通常需要一个测试应用程序来获取这些东西,但是尝试这样做:

 < DataGridTextColumn Header =RequestedBinding ={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成员

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; //或者你想要的任何颜色
}

public object [] ConvertBack(object value,Type [] targetType,object parameter,System.Globalization.CultureInfo culture)
{
抛出新的NotImplementedException();
}

#endregion
}

public class OverRequestedTooltipMultiConverter:IMultiValueConverter
{
#region IValueConverter成员

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请求的卷大于可用卷;
}
}
返回null;
}

public object [] ConvertBack(object value,Type [] targetType,object parameter,System.Globalization.CultureInfo culture)
{
throw new NotImplementedException );
}

#endregion
}

Don不要将转换器添加到你的app.xaml中:

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


I've got an editable datagrid on a WPF form inside an MVVM application.

There are two possible actions a user can take on this page that cause some data inside one of the rows to change. One of the editable fields - Requested - can cause another property to change, and there's a style trigger dependent on its value:

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

And in the 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>

The other is a button that updates the data item behind the row and changes a value on the item.

Although the datagrid itself is responsive to changes - if you add or remove rows from the underlying ObservableCollection it updates accordingly in the UI - changes to these properties on the items underneath the rows do not update.

I understand that this is by design, in the sense that changes to items inside an observableCollection do not bubble up, and have to be watched for specifically, but I'm struggling to find out how to achieve what I want.

I've tried - as suggested elsewhere - overriding the event handler for CollectionChanged on the ObservableCollection to add a notification alert to the items inside:

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

But items inside do not implement the INotifyPropertyChanged interface - they're Entity Framework objects and not ViewModels. So the cast fails.

Is there a way I can implement this? With only two properties to watch, I'd happily do it manually - but even calling OnPropertyChanged("") to update all the properties in the ViewModel doesn't cause those inside the datagrid to refresh.

解决方案

Maybe you can try it another way, using converters. I have an app that does something like that. I usually need a test app to get this stuff just right, but try this:

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

The converters would look something like this:

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
    }

Don't forget to add the converters to your app.xaml:

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

这篇关于WPF MVVM - Datagrid不更新子项的更改属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆