【问题标题】:ObservableCollection<T> binding through MVVM doesn't update the view通过 MVVM 绑定的 ObservableCollection<T> 不会更新视图
【发布时间】:2010-10-15 11:40:29
【问题描述】:

我有以下简化的 ViewModel

public class UserViewModel : IUserViewModel
{
    public DelegateCommand<object> NewUser { get; private set; }

    public ObservableCollection<UserInfo> UserList { get; set; }

    public UserViewModel( ) {
        NewUser = new DelegateCommand<object>( OnNewUser );

        this.UserList = new ObservableCollection<UserInfo>( );
        UserList.Add( new UserInfo( "Peter" );
        UserList.Add( new UserInfo( "Paul" );
        UserList.Add( new UserInfo( "Mary" );
    }

    private void OnNewUser( object parameter ) {
        UserInfo user = new UserInfo( "User"+DateTime.Now.ToLongTimeString(), 0, true, false, false );
        UserList.Add( user );
    }
}

此视图模型是(简化)视图的数据上下文:

public partial class UserView : ViewBase
{
    public UserView( UserViewModel viewModel ) {
    InitializeComponent( );

    this.DataContext = viewModel;
    }
}

视图本身包含一个绑定到 UserViewModel 的 UserList 的 ListBox:

<ListBox ItemsSource="{Binding UserList}" DisplayMemberPath="UserID" />

初始化视图模型时,它会将用户添加到列表中。该用户显示在列表框中。之后调用 NewCommand 时,会将新用户添加到列表中。但是列表框不会随新用户一起更新。

我向视图模型和视图添加了一个 CollectionChanged 处理程序。视图处理程序被添加到构造函数中,如下所示:

viewModel.UserList.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler( UserList_CollectionChanged );

[编辑]

将新用户添加到集合的命令由来自不同视图的按钮触发:

public class UserButtonBarViewModel : IUserButtonBarViewModel
{

    public UserButtonBarViewModel( IUserButtonBarView view, IUserViewModel mainModel ) {
        this.View = view;
        NewUser = mainModel.NewUser;
        this.View.Model = this;
    }

    public ICommand NewUser { get; private set; }

    public IUserButtonBarView View {get; private set; }
}

UserButtonBarView 如下所示:

<UserControl ...>
    <Button Command="{Binding NewUser}" Content="New user"/>
</UserControl>

以及背后的视图代码:

public partial class UserButtonBarView : IUserButtonBarView
{

    public UserButtonBarView( ) {
        InitializeComponent( );
    }

    public IUserButtonBarViewModel Model {
        get {
            return DataContext as IUserButtonBarViewModel;
        }
        set {
            DataContext = value;
        }
    }
}

[/编辑]

有趣的是,视图模型中的处理程序是在将新用户添加到集合时执行的,但视图的处理程序没有被调用。

为什么视图的处理程序也没有被调用?当视图模型中的集合发生变化时,为什么列表框没有自行更新?

【问题讨论】:

  • 你能贴出实际添加新用户的代码吗?

标签: wpf mvvm binding observablecollection


【解决方案1】:

听起来您正在某处(可能在您的 ButtonViewModel 中)创建 ViewModel 的第二个副本,并且您的 NewUser 按钮正在将用户添加到一个副本,而 ListBox 仍然绑定到另一个副本。

你能发布你的 NewUser 命令代码吗?

【讨论】:

  • NewUser命令的代码已经贴在第一段代码中。 NewUser 命令分配了一个指向 OnNewUser() 的新委托命令。此方法只是创建一个新的 UserInfo 实例并将其添加到集合中。
  • 依赖项通过 IoC 容器解决。容器已将 UserViewModel 的另一个实例注入到 UserButtonBarViewModel 中。将 ContainerControlledLifetimeManager 添加到 UserViewModel 后,它就可以工作了。感谢您的帮助。
【解决方案2】:

您能否发布实际添加新用户的代码? 看起来它可能发生在与 UI 不同的线程上?尝试使用 Dispatcher.Invoke...

【讨论】:

  • 我把问题移到了评论中......对不起
【解决方案3】:

我认为您需要使用双向绑定。

<ListBox ItemsSource="{Binding UserList, Mode=TwoWay}" DisplayMemberPath="UserID" />

【讨论】:

  • 对不起,但这并不能解决问题。对于 TwoWay 绑定,我是否必须拥有视图模型实施 INotifyPropertyChanged?
  • 我刚刚为自己创建了一个非常简单的测试应用程序,它似乎可以在没有双向绑定的情况下工作。我没有像你那样使用“命令”(我只是在代码隐藏中添加了一些东西),但这不重要。如果您认为有用,我可以发布代码。
  • 刚刚注意到您对不同视图的编辑。这显然与您的问题有关,所以我发布的任何内容都无济于事,对不起!
  • TwoWay 在 ItemsSource 属性上设置时不执行任何操作,因为 ItemsControls 不会更改绑定到它们的集合。为了让 TwoWay 产生任何效果,ListBox 必须在内部为其 ItemsSource 属性分配一个新的集合实例,然后将其推送到 VM 并替换之前分配给 UserList 的整个集合实例。这显然是不可取的,这就是为什么它不能那样工作。
【解决方案4】:

我看到您的 UserList 属性有一个设置器 - 当您对用户列表进行更改时,您是清除并添加到当前的 ObservableCollection,还是创建一个新的?

【讨论】:

  • 我必须道歉。没有使用设置器,我只是忘记删除它。抱歉,不过还是谢谢你。
猜你喜欢
  • 2011-08-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-29
  • 2011-10-25
  • 1970-01-01
  • 2016-05-19
  • 2013-01-02
相关资源
最近更新 更多