You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 19:05:24