【问题标题】:ListView does not update when source is changed - Even though I implemented PropertyChanged更改源时 ListView 不会更新 - 即使我实现了 PropertyChanged
【发布时间】:2016-07-29 17:58:06
【问题描述】:

我已经为这个问题苦苦挣扎了好几个小时了:

我正在以 MVVM 模式构建 UWP 应用程序。

问题:当我更改 ItemSource 的属性值时,我无法让 ListView 的 ItemSource 更新/重新绑定到 ObservableCollection 的新实例,即使我已经在该属性上实现了 IPropertyChanged。

详情: 我正在处理的页面有一个 ListView,它的 ItemSource 绑定到一个可观察的集合:

页面:

<ListView ItemsSource="{Binding Orders}" x:Name="OrderListView"><!--Inner bindings works fine--></ListView>

视图模型:

    public ObservableCollection<Order> Orders {
        get { return _Orders; }
        set { Set(ref _Orders, value); }
    }
    private ObservableCollection<Order> _Orders;
    (...)
    //Property changed implementation from video (06:48): https://mva.microsoft.com/en-US/training-courses/windows-10-data-binding-14579?l=O5mda3EsB_1405632527

    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisePropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    //If property is updated with, raise property changed, else don't
    public bool Set<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
    {
        if (Equals(storage, value))
            return false;
        storage = value;
        RaisePropertyChanged(propertyName);
        return true;
    }

在 UI 中按下按钮时:

<Button Content="Waiter" Click="Waiter_Click" Background="{Binding Waiter, Converter={StaticResource BoolToColorConverter}, FallbackValue='Yellow', TargetNullValue='Red'}"/>

它会欺骗后面代码中的“Waiter_Click”事件处理程序:

private void Waiter_Click(object sender, RoutedEventArgs e)
    {
        var viewModel = ((Button)sender).DataContext as OrderPageViewModel;
        if (viewModel.Waiter) viewModel.Waiter = false;
        else viewModel.Waiter = true;
    }

实现了 Waiter 属性,所以它在 ViewModel 中引发 PropertyChangedEvent:

public bool Waiter
    {
        get { return _waiter; }
        set { Set(ref _waiter, value); FilterView(); }
    }
private bool _waiter;

UI 中的按钮已更新 - 效果很好。

设置_waiter的私有字段后,我还想过滤掉一些不想显示的数据。

我在 FilterView() 中执行此操作;方法。 这是通过创建一个新的 ObservableCollection 并设置 Orders 属性来完成的:

    public void FilterView()
    {    
        var filteredOrderList = new ObservableCollection<Order>();
        //Sorting is done
        Orders = filteredOrderList;
    }

现在。我以为代码: Orders = filteredOrderList;将触发 Orders 属性的“设置器”,并引发 PropertyChanged 事件,就像它对按钮和所有其他正常工作的 UI 元素所做的那样 - 并告诉 ListView 重新绑定到它。但是,ListView 似乎在 ObservableCollection 的旧实例上运行,并且不关心我的 PropertyChanged 事件被触发...

我已经调试了程序,我看到filteredOrderList 包含我想要的数据,并且Orders 发生了变化。但这就像 ViewList 不关心 PropertyChanged 事件被触发...

我不想在 ObservableCollection 中添加和删除项目,因为过滤变得非常复杂...我只想用新的替换 Orders ObservableCollection,并让 ViewList 反映我的更改...

我错过了什么吗?我不能多次调用 PropertyChanged 事件吗? (我调用一次是为了更新按钮,一次是为了更改 Orders ObservableCollection)。

为什么 ListView 没有重新绑定到新列表? -ListView 不关心 PropertyChanged 事件被触发吗?

我将非常感谢任何可以解决此问题或向我发送正确方向的答案或解决方法。

谢谢你,很抱歉发了这么长的帖子。

【问题讨论】:

  • 有没有办法手动更新 ViewList?没有从它的 ItemSource 添加或删除项目?

标签: c# xaml listview observablecollection propertychanged


【解决方案1】:

【讨论】:

  • 感谢您的回答。我已经阅读了“常见错误...”文章,这很有意义:) 我可能会再看一下“Sort ObservableCollection C#”。以另一种方式找到了我的解决方案。坦克你。
【解决方案2】:

8个半小时后我发现了我的错误:

我不小心定义了两次 DataContext:

<Page.DataContext>
    <vm:OrderPageViewModel/>
</Page.DataContext>

在 ListView 之前的 XAML 文件中进一步向下:

<Grid.DataContext>
    <vm:OrderPageViewModel/>
</Grid.DataContext>

这导致了我的 OrderPageViewModel 的两个实例。

然后,我的 ViewList 被绑定到 ViewModel 的旧实例,对 ObservableCollection 的新 ViewModel 实例的任何更改都不会反映任何更改。

如果其他人遇到同样的问题:更改 ObservableCollection 时 ViewList 不会更新 - 这很正确,因为您创建了 ObservableCollection 的多个实例。

我还发现 ObservableCollection 仅在添加 og 从其中删除对象并使用 .Add()、.Remove() 和 .Clear() 方法清除它时才会更新。像我在 Waiter 属性上所做的那样,如果不在属性本身中实现它,就不能调用“CollectionChanged”或“PropertyChanged”。

我重新制作了过滤功能以清除集合并向其中添加新元素。它解决了我的问题。 :-)

如果你不小心的话,XAML 中的 3 行代码真的会搞砸你的一天。

祝你有美好的一天,感谢发布之前答案的人:-)

【讨论】:

  • 这似乎很奇怪 2 我你甚至可以更改每个 ui 元素的 DataContext,不是吗?
  • @MatthiasHerrmann - 您可以全局指定元素的数据上下文(就像我在 Page 中所做的那样),每个子元素都将具有此数据上下文。现在,如果我想为页面元素中的子元素使用不同的数据上下文,我必须像使用网格一样指定另一个数据上下文。然后,网格及其子元素可以绑定到全局数据上下文中未指定的其他数据。有人会在某处使用它是很有意义的。但是我的错误是,我两次将相同的对象指定为 datacontext,从而产生了一个新的实例,我不知道因此出现了这个错误。
猜你喜欢
  • 2014-08-15
  • 1970-01-01
  • 2013-04-25
  • 1970-01-01
  • 2011-12-23
  • 2013-10-11
  • 2014-11-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多