我用 2 ListBox
创建了一个 WPF 用户控件es(命名为“Source”和“Value”)和一个“Add”按钮,允许用户“复制”绑定(bind)到 Source ListBox
的项目值 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);
}
}
}
我使用此用户控件的 View 是使用 MVVM Light。这是我的 ViewModel 代码,它公开了绑定(bind)到每个 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>();
}
}
}
绑定(bind)工作正常。问题是,当用户在“源”列表框中选择项目并单击“添加”按钮时,当此行在 btnAdd_Click 事件处理程序的用户控件后面的代码中执行时,我得到一个错误:
listBoxValue.Items.Add(o);
我收到的错误是:“使用 ItemSource 时操作无效。改为使用 ItemsControl.ItemsSource 访问和修改元素。所以,我理解这个问题,但我不知道解决这个问题的最佳方法。 DependencyProperties 是 IEnumerable 类型的,所以我不能直接在用户控件后面的代码中添加它们。此外,我无法访问 ViewModel 并直接更新属性,因为用户控件库无法为 View 引用 ViewModel。将项目从“源”列表框复制到“值”列表框的最佳方法是什么(最好将代码包含在用户控件中,而不是要求 View/ViewModel 添加项目)。此外,这是一个用户控件,因此绑定(bind)到每个列表框的类型随控件的每次使用而变化。
编辑 - 2011 年 10 月 4 日
所以,真正的问题是如何从我的用户控件中更新(添加到)“值”列表?依赖属性是 IEnumerable 类型的,所以不能直接更新,而且如上面的错误所示,我不能简单地调用 listbox.items.Add()。我正在使用 MVVM,因此需要对 ViewModel 中公开的属性进行数据绑定(bind)。此外,用户控件不知道(也不应该知道)在运行时绑定(bind)到它的类型。我意识到我的用户控件可以引发可以通过 MVVM Light 中的 EventToCommand 功能处理的“已添加”事件,但这似乎没有必要 - 如果我从需要我的第 3 方控件供应商处购买控件,我个人不会满意自己更新收藏。我知道这是可能的,因为这本质上是组合框的工作方式 - 组合框同时具有 ItemsSource 属性和 SelectedValue 属性,它们可以绑定(bind)到 ViewModel 上的属性。
<ComboBox
ItemsSource="{Binding Path=Categories}"
DisplayMemberPath="Name"
SelectedValue="{Binding Path=SelectedCategory, Mode=TwoWay}"/>
最佳答案
Items
和 ItemsSource
是互斥的,一次ItemsSource
设置为 Items.Add(..)
会扔。不要使用 ItemsSource
即使它是最简单的选项,请使用 Items.Add
在循环中(您可以从 DP 值更改事件处理程序中调用它)。
如果您需要任何进一步的帮助,请告诉我。
关于wpf - 列表框和 MVVM 的用户控制数据绑定(bind)问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7640866/