如何更新绑定列表的现有项目时如何更新ListView

时间:2012-03-30 14:14:37

标签: wpf

我需要在更改进度时更新下载列表。

XAML:

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

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

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(() => MyListView.Items.Refresh()));

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

  3. 两种方式都会导致问题:应按用户要求打开的ListView 闪烁弹出始终在每次“刷新”后关闭

    Popup

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

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

    PS:很抱歉很长时间的问题,但我不知道如何更简短地描述它......

2 个答案:

答案 0 :(得分:1)

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

RaisePropertyChanged("UiList"); 

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

答案 1 :(得分:0)

我在这里找到了答案: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; }
}