【问题标题】:User Control databinding issue with listbox and MVVM列表框和 MVVM 的用户控制数据绑定问题
【发布时间】:2011-11-30 06:00:24
【问题描述】:

我创建了一个 WPF 用户控件,其中包含 2 个 ListBoxes(名为“源”和“值”)和一个“添加”按钮,允许用户“复制”绑定到源 @987654322 的项目@ 值ListBox。代码如下:

public partial class MultiListSelect : UserControl
{
    public static readonly DependencyProperty ListSourceProperty;
    public static readonly DependencyProperty ListValueProperty;

    public IEnumerable ListSource  
    {
        get { return (ObservableCollection<object>)GetValue(MultiListSelect.ListSourceProperty); } 
        set { SetValue(MultiListSelect.ListSourceProperty, value); }  
    }

    public IEnumerable ListValue
    {
        get { return (ObservableCollection<object>)GetValue(MultiListSelect.ListValueProperty); }
        set { SetValue(MultiListSelect.ListValueProperty, value); }
    }  


    public MultiListSelect()
    {
        InitializeComponent();
    }

    static MultiListSelect()  
     { 

         MultiListSelect.ListSourceProperty =  
            DependencyProperty.Register("ListSource",
            typeof(IEnumerable), typeof(MultiListSelect));

         MultiListSelect.ListValueProperty =
            DependencyProperty.Register("ListValue",
            typeof(IEnumerable), typeof(MultiListSelect));

     }

    private void btnAdd_Click(object sender, RoutedEventArgs e)
    {
        foreach (object o in listBoxSource.SelectedItems)
        {
             listBoxValue.Items.Add(o);
        }
    }

}

我使用此用户控件的视图正在使用 MVVM Light。这是我的 ViewModel 代码,它公开了绑定到每个 ListBox 的数据:

public class ProfileViewModel : ViewModelBase
{
    public User User { get; set; }

    // This gets bound to the Source listbox
    private ObservableCollection<OperatingArea> _operatingAreas;
    public ObservableCollection<OperatingArea> OperatingAreas 
    { 
        get { return _operatingAreas; }
        private set
        {
            _operatingAreas = value;
        }
    }

    public ProfileViewModel()
    {
        OperatingAreas = _rpDomain.LoadOperatingAreas();
        WindowsIdentity identity = WindowsIdentity.GetCurrent();

        if (User == null)
        {
            User = _rpDomain.CreateUser();
            User.Preferences = _rpDomain.CreateUserPreferences();
            User.UserId = identity.Name;

            _rpDomain.Add(User);
        }

        if (User.Preferences == null)
        {
            User.Preferences = _rpDomain.CreateUserPreferences();
        }

        if (User.Preferences.ViewableOperatingAreas == null)
        {
            // This gets bound to my 'Value' ListBox
            User.Preferences.ViewableOperatingAreas = new ObservableCollection<OperatingArea>();
        }
    }
}

绑定工作正常。问题是当用户在“源”列表框中选择项目并单击“添加”按钮时,在 btnAdd_Click 事件处理程序的用户控件后面的代码中执行此行时出现错误:

listBoxValue.Items.Add(o);

我收到的错误是:'使用 ItemSource 时操作无效。改为使用 ItemsControl.ItemsSource 访问和修改元素。所以,我理解这个问题,但我不知道解决这个问题的最佳方法。 DependencyProperties 是 IEnumerable 类型的,所以我不能直接在用户控件后面的代码中添加它们。此外,我无法访问 ViewModel 并直接更新属性,因为用户控件库无法为视图引用 ViewModel。将项目从“源”列表框复制到“值”列表框的最佳方法是什么(最好将代码包含在用户控件中,而不是要求 View/ViewModel 添加项目)。此外,这是一个用户控件,因此绑定到每个列表框的类型随控件的每次使用而变化。

编辑 - 2011 年 10 月 4 日

那么,真正的问题是如何从我的用户控件中更新(添加到)“值”列表?依赖属性是 IEnumerable 类型的,所以不能直接更新,而且如上面的错误所示,我不能简单地调用 listbox.items.Add()。我正在使用 MVVM,因此需要对 ViewModel 中公开的属性进行数据绑定。此外,用户控件不知道(也不应该知道)在运行时绑定到它的类型。我意识到我的用户控件可以引发可以通过 MVVM Light 中的 EventToCommand 功能处理的“已添加”事件,但这似乎没有必要 - 如果我从需要我的第 3 方控件供应商处购买控件,我个人不会满意自己更新收藏。我知道这是可能的,因为这本质上是组合框的工作方式 - 组合框同时具有 ItemsSource 属性和 SelectedValue 属性,可以绑定到 ViewModel 上的属性。

<ComboBox 
    ItemsSource="{Binding Path=Categories}"
    DisplayMemberPath="Name"
    SelectedValue="{Binding Path=SelectedCategory, Mode=TwoWay}"/> 

【问题讨论】:

    标签: wpf data-binding mvvm user-controls


    【解决方案1】:

    ItemsItemsSource 是互斥的,一旦ItemsSource 被设置为某个东西,Items.Add(..) 就会抛出。不要使用ItemsSource,即使它是最简单的选项,请在循环中使用Items.Add(您可以从DP值更改事件处理程序中调用它)。

    如果您需要任何进一步的帮助,请告诉我。

    【讨论】:

    • 如果我按照您的建议进行操作,我看不到 ViewModel 中的绑定属性(集合)如何使用添加到“值”列表框中的新项目进行更新。我错过了什么吗?
    • 好的,但是如何从我的用户控件中更新依赖属性 (IEnumerable)? IEnumerable 是只读的。
    • 对不起,是什么迫使您使用 IEnumerable 而不是 List?该物业归您所有,您有权决定其类型,不是吗?
    • List 不是我的视图模型中提供的类型。我的视图模型中的类型类似于 ObservableCollection。所以我可以为我的 DP 使用该类型,但用户控件只能用于该类型。它需要适用于任何类型的 ObservableCollection。再次感谢您帮助我解决这个问题。如果您有解决此问题的其他想法,请告诉我。
    • 我从来都不是 mvvvm 的忠实粉丝。您将学到的只是一组令人讨厌的技巧。在某个时间点,你会开始认为你喜欢它。视图是一个被动层,想想它。您需要做的是从 V 向 MV 发出命令,通知您的 MV 您的操作。这是在任何 MV* 框架中做事的规范方式。一旦您的 MV 收到该消息,它应该将您选择的项目添加到您的 ListValue DP - 在该阶段您的 ValueList 将得到更新(感谢 ObservableCollection 功能)。这有意义吗?
    猜你喜欢
    • 2011-04-07
    • 2010-12-15
    • 2011-02-26
    • 1970-01-01
    • 2012-05-10
    • 1970-01-01
    • 1970-01-01
    • 2010-11-22
    • 1970-01-01
    相关资源
    最近更新 更多