3

C#:

public partial class MainWindow : Window
{
    private readonly ViewModel vm;

    public MainWindow()
    {
        InitializeComponent();
        vm = new ViewModel();

        DataContext = vm;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        vm.Models.RemoveAt(0);
    }
}

public class ViewModel
{
    public ObservableCollection<Model> Models { get; set; }
    public ListCollectionView View { get; set; }

    public ViewModel()
    {
        Models = new ObservableCollection<Model>()
        {
            new Model() { Name = "Gordon Freeman" },
            new Model() { Name = "Isaac Kleiner" },
            new Model() { Name = "Eli Vance" },
            new Model() { Name = "Alyx Vance" },
        };

        Models.CollectionChanged += (s, e) => View.Refresh();
        View = new ListCollectionView(Models);
    }
}

public class Model
{
    public string Name { get; set; }

    public override string ToString()
    {
        return Name;
    }
}

XAML:

<StackPanel>
    <ListBox ItemsSource="{Binding Path=View}" />
    <Button Click="Button_Click">Click</Button>
</StackPanel>

ObservableCollection 包含 4 个元素,并且 ListBox 显示所有 4 个,如预期的那样。单击按钮时,ObservableCollection 的第一个元素被删除。然而,ListBox 现在只显示第二个和第三个。似乎第一个和第四个已被删除。

如果该行在(或完全注释掉)之后Models.CollectionChanged += (s, e) => View.Refresh();移动,事情会按预期工作。 View = new ListCollectionView(Models);

为什么?

PS这是一个更大的难题的一个简单部分。在这个小例子中,我意识到我不需要调用View.Refresh();CollectionChanged 来让 ListBox 进行自我更新。

4

4 回答 4

1

我的猜测是刷新会干扰视图的自动更新。大概视图CollectionChanged在构造函数中也订阅了,所以如果您在视图之前订阅事件并调用刷新,您会在集合更改和视图自己的更新之间获得不需要的更新。

例如

项目 0 被删除 -> 通知事件侦听器
=> 你的处理程序:刷新() -> 重建视图 => 项目被删除。
=> 查看处理程序:事件参数说:项目 X 已删除 -> 删除项目 X

这仍然不能解释为什么第一个和最后一个项目被删除,但对我来说似乎是合理的。

如果订阅是在视图实例化之后:

项目 0 已删除 -> 通知事件侦听器
=> 视图处理程序:事件参数说:项目 X 已删除 -> 删除项目 X
=> 您的处理程序:刷新() -> 重建视图 => 没有改变。

于 2012-01-10T19:01:14.650 回答
1

似乎是 ListView 刷新的问题。如果将 labe/TextBlock 绑定到 ListView.Items.Count,您会看到列表仍然有 3 个项目(第一次删除后)。

于 2012-01-10T19:21:51.290 回答
1

即使你将你的Model类包装在一个 中ObservableCollection,你仍然需要INotifyPropertyChanged为它实现。我已经对这个问题进行了足够多的尝试,现在我记得从最低的构建块开始进行故障排除,即Model.

public class Model : INotifyPropertyChanged
{
    #region INotify Implementation
    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
    #endregion

    public string _Name;
    public string Name {
        get { return _Name;  }
        set { _Name = value; NotifyPropertyChanged("Name"); }

    }
    public override string ToString()
    {
        return Name;
    }
}

此外,在您的ViewModel, whenINotifyPropertyChanged正确实施时,您不需要以下几行。 INotifyPropertyChanged将为您更新您的用户界面。

    Models.CollectionChanged += (s, e) => View.Refresh();
    View = new ListCollectionView(Models);
于 2017-03-08T06:31:49.687 回答
-1

尽量不要使用 new 关键字来定义新的listCollectionView. 请改用以下内容。

var sortedCities  = CollectionViewSource.GetDefaultView(Models);
于 2013-12-18T17:38:20.897 回答