WPF ListBox绑定数据源更新不触发(新增项正常)问题求助
问题场景
系统包含层级对象:Order(对应代码中的OneOff)→ Store → Planogram,均继承自实现INotifyPropertyChanged的基类,通过MVVM Toolkit实现属性变更通知,所有属性变更会自动设置IsDirty=true。子集合的CollectionChanged事件已绑定,用于向上传递变更。
ViewModel维护ObservableCollection<OneOff>,ListBox绑定该集合,ItemTemplate内的TextBlock通过转换器绑定IsDirty属性来显示*标记。
异常现象
- 修改从数据库加载的Order的任意子属性时,
IsDirty已被正确设置为true,但ListBox中对应的*始终不显示。 - 新增空白Order并添加到集合后,*能正常显示。
相关代码片段
包含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对象代码片段
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"); }
ViewModel集合定义部分
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>
问题分析与解决方案
核心问题
从数据库加载的对象,其层级变更没有传递到最上层的OneOff对象的IsDirty属性变更通知,或者OneOff对象的IsDirty变更未触发UI更新。
具体排查点与修复方案
补全层级变更传递链
当前Store对象的子集合变更仅触发了OneOffStorePlanograms的属性通知,未传递到父级OneOff对象。需在OneOff对象中为其包含的Store集合绑定CollectionChanged事件,同时为每个Store对象绑定PropertyChanged事件,当Store的属性或子集合变更时,设置OneOff的IsDirty=true。检查基类事件逻辑
基类中重写OnPropertyChanged时,先调用base.OnPropertyChanged(e)再设置IsDirty=true,需确保子对象的变更能向上传递到OneOff,触发其IsDirty的变更通知。确认OneOff类正确继承自BaseOneOffStorePlanogram。修复数据库加载对象的事件绑定缺失
新增空白Order时会自动绑定子集合事件,但从数据库加载的对象,未为已存在的子对象(Store、Planogram)绑定PropertyChanged事件。在LoadOneOffs方法中,遍历每个加载的OneOff及其下的Store,为Store的PropertyChanged事件绑定处理程序,同时为Store的Planogram集合中已存在的每个Planogram绑定PropertyChanged事件。验证UI绑定正确性
确认BoolToVis转换器逻辑正确:当IsDirty=true时返回Visibility.Visible,否则返回Collapsed或Hidden。可在OneOff的IsDirtysetter中添加调试输出,确认修改子属性时确实触发了IsDirty变更和OnPropertyChanged("IsDirty")调用。
内容的提问来源于stack exchange,提问作者KYoung19

