WPF 列表框更新绑定数据源不触发更新(但新插入会)

问题描述 投票:0回答:1

我刚刚回到 WPF/XAML 编程,遇到了一个我无法弄清楚的问题。我有一个对象,可以把它想象成一个订单,每个订单包含一个 Store 对象列表,每个 Store 包含一个 Planogram 对象列表。未处理的订单从数据库中检索并放入一个可观察的集合中。

使用 MVVM 工具包,每个属性都使用 INotify 来指示属性何时更改。这还会设置 IsDirty 标志,指示已进行更改。 Store 对象和 Order 对象都有一个事件处理程序附加到子列表的集合更改事件,以指示某些包含的元素已更改。

视图模型包含可观察的订单集合,并且在该列表的集合更改事件上还有一个事件处理程序,因此可以更新表单。

表单有一个包含订单名称的列表框。选择订单后,详细信息将显示在表单的其他控件上。

这就是背景...这就是问题所在...我在每个订单名称的列表框的项目模板中都有一个文本块。使用 BoolToVis 转换器将可见性绑定到 Is Dirty 标志。如果我选择一个订单并对任何子属性进行更改,更改会向上冒泡到父级并且正确设置了 is dirty 标志。但是源永远不会更新,文本框中的“*”永远不会显示。

但是,可以选择添加空白订单。创建一个空白订单并将其添加到订单列表中。此时,新订单显示在列表框中,订单名称旁边带有 *。

我已经搜索了几天并通读了我能在 SO 上找到的所有内容。我所看到的大多数是人们没有对属性进行 INotify 设置。我知道,我发现的每个答案都说这应该有效……但事实并非如此。

包含 IsDirty 标志的基础对象

public class BaseOneOffStorePlanogram : ObservableObject, IOneOffData
    {
        private bool _isDirty = false;
        

        public bool IsDirty 
        { 
            get { return _isDirty; } 
            set { 
                if(value != _isDirty)
                {
                    _isDirty = value;
                    base.OnPropertyChanged("IsDirty");
                }
            } 
        } 
        public string LastModifiedBy { get; set; }
        public DateTime? LastModifiedOn { get; set; }

        protected override void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (e.PropertyName != "IsDirty")
            {
                base.OnPropertyChanged(e);

                IsDirty = true;
            }
         }

       
    }

这是 Store 对象的一个片段,其中每个属性都调用 OnPropertyChanged 事件,也是我更改了 Collection 的地方。


        public string StoreNumber
        {
            get { return _StoreNumber; }
            set
            {
                _StoreNumber = value;
                base.OnPropertyChanged("StoreNumber");
            }
        }
        public DateTime? PricingDateOverride
        {
            get
            {
                return _PricingDateOverride;
            }
            set
            {
                _PricingDateOverride = value;
                base.OnPropertyChanged("PricingDateOverride");
            }
        }

     public OneOffStore()
        {
            _OneOffStorePlanograms = new ObservableCollection<OneOffStorePlanogram>();
            _OneOffStorePlanograms.CollectionChanged += _OneOffStorePlanograms_CollectionChanged;
          
        }

        private void _OneOffStorePlanograms_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if(e.OldItems != null)
            {
                foreach( OneOffStorePlanogram oosp in e.OldItems)
                {
                  oosp.PropertyChanged += InvokeCollectionChanged;
                }
            }
            if( e.NewItems != null)
            {
                foreach(OneOffStorePlanogram oosp in e.NewItems)
                {
                    oosp.PropertyChanged += InvokeCollectionChanged;
                }
            }
        }

        private void InvokeCollectionChanged(object sender, PropertyChangedEventArgs e)
        {
            OnPropertyChanged("OneOffStorePlanograms");
        }

这是定义可观察集合的视图模型部分


     public ObservableCollection<OneOff> OneOffs
        {
            get { return _oneOffs; }
        }

     private void InitializeForm(){
            _oneOffs = new ObservableCollection<OneOff>();

            _selectedStores = new ObservableCollection<Store>();
            _selectedPlanograms = new ObservableCollection<Models.Planogram>();
            _useEffectiveDate = false;
           
            LoadPlanograms();
            LoadStores();
            LoadOneOffs();
            //GetUnprocessedOneOffs();
           
            _oneOffs.CollectionChanged += OneOffs_CollectionChanged;`
          }

这是 XAML 片段

 <ListBox x:Name="lstActiveJobs"   VerticalAlignment="Stretch" HorizontalAlignment="Stretch" ItemsSource="{Binding OneOffs, NotifyOnSourceUpdated=True,UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding SelectedOneOff}" >

                                    <ListBox.ItemTemplate>
                                        <DataTemplate>
                                            <Grid>
                                                <Grid.ColumnDefinitions>
                                                    <ColumnDefinition Width="*"/>
                                                    <ColumnDefinition Width="10"/>
                                                </Grid.ColumnDefinitions>
                                                <Grid.RowDefinitions>
                                                    <RowDefinition Height="*"/>
                                                </Grid.RowDefinitions>
                                                <TextBlock Text="{Binding OneOffName, PresentationTraceSources.TraceLevel=High}" Grid.Row="0" Grid.Column="0" />
                                                <TextBlock Text="*" x:Name="HasChangeModifier" Grid.Row="0" Grid.Column="1"  Visibility="{Binding IsDirty, Converter={StaticResource BoolToVis}, UpdateSourceTrigger=PropertyChanged}"/>
                                            </Grid>

                                        </DataTemplate>
                                    </ListBox.ItemTemplate>
                                </ListBox>

我确定这很简单,或者我做错了。让我感到困惑的是,新添加的、未保存的项目有效,但从数据库中检索到的项目却没有。

任何建议将不胜感激。

c# .net wpf xaml
1个回答
1
投票

重写的

OnPropertyChanged(PropertyChangedEventArgs e)
方法不会为
base.OnPropertyChanged(e)
属性调用
IsDirty
,因此不会通知该属性的绑定。

方法应该是这样的:

protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
    if (e.PropertyName != nameof(IsDirty))
    {
        IsDirty = true;
    }
    base.OnPropertyChanged(e);
}

注意

OnPropertyChanged(PropertyChangedEventArgs e)
OnPropertyChanged(string propertyName)
调用。

© www.soinside.com 2019 - 2024. All rights reserved.