用户控件数据绑定问题与列表框和MVVM

时间:2011-10-03 21:26:29

标签: wpf data-binding mvvm user-controls

我创建了一个WPF用户控件,其中包含2个ListBox es(名为“Source”和“Value”)和一个“Add”按钮,允许用户“复制”绑定到Source的项目值ListBox的{​​{1}}。这是代码:

ListBox

我认为使用此用户控件的视图是使用MVVM Light。这是我的ViewModel代码,它公开了绑定到每个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);
        }
    }

}

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

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>();
        }
    }
}

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

编辑 - 10-4-2011

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

listBoxValue.Items.Add(o);

1 个答案:

答案 0 :(得分:0)

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

如果您需要任何进一步的帮助,请与我们联系。