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

sshcrbum  于 2023-03-10  发布在  其他
关注(0)|答案(1)|浏览(221)

我刚刚回到WPF/XAML编程中,遇到了一个我无法解决的问题。我有一个对象,可以将其视为一个订单,每个订单包含一个Store对象列表,每个Store包含一个Planogram对象列表。未处理的订单从数据库中检索出来,并放入一个可观察的集合中。
使用MVVM工具包时,每个属性都使用INotify来指示属性的更改时间。这还会设置IsDirty标志,以指示已进行更改。Store对象和Order对象都有一个附加到子列表的集合更改事件的事件处理程序,以指示某些包含的元素已更改。
视图模型包含可观察的订单集合,并且还有一个关于该列表的集合更改事件的事件处理程序,因此表单可以更新。
该窗体有一个列表框,其中包含订单的名称。选定订单后,详细信息将显示在窗体的其他控件上。
这是背景...问题在这里...我在列表框的项目模板中为每个订单名称设置了一个文本块。使用BoolToVis转换器将可见性绑定到Is Dirty标志。如果我选择了一个订单并更改了任何子属性,这些改变会被传递到父文件,并且修改标志被正确设置。2但是源文件不会被更新,文本框中的“*”也不会被显示。
但是,可以选择添加空白订单。创建空白订单并将其添加到订单列表中。此时,新订单显示在列表框中,订单名称旁边带有 *。
我已经搜索了几天,阅读了所有我能在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 changed。

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>

我确信这是简单的事情,或者我做错了。让我困惑的是,新添加的,未保存的项目工作,但从数据库检索的项目不工作。
任何建议都将不胜感激。

xkftehaa

xkftehaa1#

被重写的OnPropertyChanged(PropertyChangedEventArgs e)方法不为IsDirty属性调用base.OnPropertyChanged(e),因此不通知到该属性的绑定。
该方法应如下所示:

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

请注意,OnPropertyChanged(PropertyChangedEventArgs e)OnPropertyChanged(string propertyName)调用。
需要注意的是,使用CommunityToolkit.MVVM,您不需要自己编写属性声明,只需使用ObservableProperty属性即可:

public partial class BaseOneOffStorePlanogram : ObservableObject, IOneOffData
{
    [ObservableProperty] // this will generate the IsDirty property
    private bool isDirty;

    ...

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

相关问题