添加INotifyPropertyChanged后ListView值不再更新的问题及进度条绑定咨询
问题描述
原本将字典值绑定到ListView,ListView可根据ComboBox选中的字典键动态更新。但给ViewModel添加INotifyPropertyChanged接口后,即便ListView和ComboBox未调用PropertyChanged相关方法,ListView也无法再更新;移除该接口则恢复正常,无报错信息。添加该接口是为了实现进度条数据绑定,同时希望了解无需INotifyPropertyChanged实现进度条绑定的方法。
Model代码
public class Example { private string _name; public string Name { get { return _name; } set { _name = value; } } public string[] GirlClothes = new string[] { "a", "b", "c" }; public string[] BoyClothes = new string[] { "a", "b" }; }
ViewModel代码
public class ExampleViewModel : INotifyPropertyChanged { public RelayCommand<IList> Submit { get; } private Dictionary<Example, string[]> _example; public Dictionary<Example, string[]> Examples { get { return _example; } set { _example = value; } } private KeyValuePair<Example, string[]> _selectedItem; public KeyValuePair<Example, string[]> SelectedItem { get => _selectedItem; set => _selectedItem = value; } public ExampleViewModel() { Example lb = new Example(); Examples = new Dictionary<Example, string[]>(); Examples.Add(new Example() { Name = "Mark" }, lb.BoyClothes); Examples.Add(new Example() { Name = "Sally" }, lb.GirlClothes); Submit = new RelayCommand<IList>(ExecuteSubmit); } private void ExecuteSubmit(IList selectedItems) { var selectedScreens = selectedItems .Cast<string>().ToList(); return; } // 移除这部分代码时ListView动态更新正常 public event PropertyChangedEventHandler PropertyChanged; public void RaisePropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } }
XAML代码
<Window.Resources> <viewmodel:ExampleViewModel x:Key="vm"></viewmodel:ExampleViewModel> </Window.Resources> <StackPanel Orientation="Horizontal" DataContext="{Binding Source={StaticResource vm}}"> <StackPanel Grid.Row="0" Grid.Column="1"> <TextBlock>Name</TextBlock> <ComboBox ItemsSource="{Binding Path=Examples}" SelectedItem="{Binding SelectedItem}" DisplayMemberPath="Key.Name" SelectedIndex="0" /> </StackPanel> <ListView ItemsSource="{Binding SelectedItem.Value}" x:Name="pageListView" Width=" 200"> <ListView.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Vertical"></StackPanel> </ItemsPanelTemplate> </ListView.ItemsPanel> <ListView.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <CheckBox IsChecked="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem}}"/> <TextBlock Text="{Binding}" /> </StackPanel> </DataTemplate> </ListView.ItemTemplate> </ListView> <Button x:Name="Submit_Btn" Command="{Binding Submit}" CommandParameter="{Binding SelectedItems, ElementName=pageListView}">Submit</Button> </StackPanel>
解决方案
1. 修复ListView不更新问题
当ViewModel实现INotifyPropertyChanged后,WPF绑定系统会依赖属性变更通知来更新UI。你的SelectedItem属性在赋值时没有触发PropertyChanged事件,导致UI无法感知到选中项的变化,进而ListView的数据源没有更新。修改SelectedItem的setter即可解决:
private KeyValuePair<Example, string[]> _selectedItem; public KeyValuePair<Example, string[]> SelectedItem { get => _selectedItem; set { _selectedItem = value; RaisePropertyChanged(nameof(SelectedItem)); } }
同时建议给Examples属性也加上变更通知,避免后续修改字典实例时出现类似问题:
private Dictionary<Example, string[]> _example; public Dictionary<Example, string[]> Examples { get { return _example; } set { _example = value; RaisePropertyChanged(nameof(Examples)); } }
2. 无需INotifyPropertyChanged实现进度条绑定
可以通过**依赖属性(DependencyProperty)**实现,依赖属性自带变更通知机制,无需实现INotifyPropertyChanged。步骤如下:
- 创建一个继承
DependencyObject的类,定义进度值的依赖属性:
public class ProgressData : DependencyObject { public static readonly DependencyProperty ProgressValueProperty = DependencyProperty.Register(nameof(ProgressValue), typeof(int), typeof(ProgressData), new PropertyMetadata(0)); public int ProgressValue { get => (int)GetValue(ProgressValueProperty); set => SetValue(ProgressValueProperty, value); } }
- 在XAML中创建该类的实例作为资源:
<Window.Resources> <local:ProgressData x:Key="progressData" /> </Window.Resources>
- 绑定进度条的
Value属性:
<ProgressBar Value="{Binding ProgressValue, Source={StaticResource progressData}}" />
- 在代码中更新进度值:
var progressData = (ProgressData)FindResource("progressData"); progressData.ProgressValue = 50; // 进度条会自动更新
内容的提问来源于stack exchange,提问作者KarkMump
相关产品推荐
相关产品推荐

