【问题标题】:How to update ListView when existent items of bound list has been updated当绑定列表的现有项目已更新时如何更新 ListView
【发布时间】:2012-03-30 14:14:37
【问题描述】:

当进度发生变化时,我需要更新下载列表。

XAML:

<ListView ItemsSource="{Binding UiList}" x:Name="MyListView">
  <ListView.View>
    <GridView>
      <GridViewColumn Header="Title"/>
      <GridViewColumn Header="Progress"/>
    </GridView>
  </ListView.View>
</ListView>

创建Logic类实例并更新ListView内容的ViewModel:

class MainWindowViewModel : ViewModelBase
{
    private readonly Logic _logic;
    public List<Model> UiList { get; set; }        

    public MainWindowViewModel()
    {
        _logic = new Logic();
        _logic.Update += LogicUpdate;
        Start = new RelayCommand(() =>
                                     {
                                         var worker = new BackgroundWorker();
                                         worker.DoWork += (sender, args) => _logic.Start();
                                         worker.RunWorkerAsync();
                                     });
    }

    void LogicUpdate(object sender, EventArgs e)
    {
        UiList = _logic.List;
        RaisePropertyChanged("UiList");            
    }

    public ICommand Start { get; set; }
}

逻辑:

public class Logic
{
    readonly List<Model> _list = new List<Model>();
    public event EventHandler Update;

    public List<Model> List
    {
        get { return _list; }
    }

    public void Start()
    {
        for (int i = 0; i < 100; i++)
        {
            _list.Clear();
            _list.Add(new Model{Progress = i, Title = "title1"});
            _list.Add(new Model { Progress = i, Title = "title2" });

            var time = DateTime.Now.AddSeconds(2);
            while (time > DateTime.Now)
            { }

            Update(this, EventArgs.Empty);
        }
    }
}

上面的代码不会更新 UI。我知道如何解决这个问题的两种方法:

  1. 在 xaml 代码隐藏调用中:Application.Current.Dispatcher.Invoke(new Action(() =&gt; MyListView.Items.Refresh()));

  2. 在 ViewModel 中将 List&lt;&gt; 更改为 ICollectionView 并在列表更新后使用 Application.Current.Dispatcher.Invoke(new Action(() =&gt; UiList.Refresh()));

这两种方式都会导致问题:应该根据用户需求打开的 ListView 闪烁Popup 总是在每次“刷新”后关闭:

<Popup Name="Menu" StaysOpen="False">

我可以用另一个控件或面板替换弹出窗口,但我需要它可能超出主窗口的边框(如屏幕上)。但我相信 WPF 有另一种方式来更新 ListView 的内容(不闪烁)。

PS:抱歉问了这么长的问题,但我不知道如何更简单地描述它......

【问题讨论】:

  • 您应该将 List 更改为 ObservableCollection。

标签: wpf


【解决方案1】:

认为这条线不起作用的原因:

RaisePropertyChanged("UiList"); 

是因为您实际上并没有更改列表。您清除它并重新填充它,但它仍然是对同一列表的引用。如果您实际上创建了一个新列表,而不是清除列表并重新填充,我很想看看会发生什么。我认为应该按您的预期更新您的 ListView。对你的弹窗有没有影响,我不知道。

【讨论】:

  • 是的,创建一个新列表为我提供了一种修复列表视图更新的新方法(顺便说一句,谢谢!)。但它不能解决弹出问题...
【解决方案2】:

我在这里找到了答案:How do I update an existing element of an ObservableCollection?

ObservableCollection 是部分解决方案。 ObservableCollection 仅在集合更改(添加、删除项目等)时触发 CollectionChanged 事件。为了支持现有项目的更新,集合内的每个对象(在我的例子中为 Model 类)必须实现 INotifyPropertyChanged 接口。

// I used this parent (ViewModelBase) for quick testing because it implements INotifyPropertyChanged
public class Model : ViewModelBase 
{
    private int _progress;
    public int Progress
    {
        get { return _progress; }
        set
        {
            _progress = value;
            RaisePropertyChanged("Progress");
        }
    }

    public string Title { get; set; }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多