WPF/Silverlight: How to bind ItemsControl based UI element to an ItemsControl property on the ViewModel?
Being a new to WPF/XAML/MVVM, I've got a question.
In my View, I have 2 listboxes, which derive from ItemsControl. On my viewmodel, I'd like to expose 2 ItemsControl properties such that I can bind my listbox to this view model property... this way I can implement a command that, from the view model, lets me move the currently selected item from ListBox1 to ListBox2.
Imagine all the really cool stuff not shown the following snippets:
view model code:
public int MyStuff1SelectedIndex { get{...} set{...} }
public int MyStuff2SelectedIndex { get{...} set{...} }
public ItemsControl MyStuffItemsControl1 { set; private get; }
public ItemsControl MyStuffItemsControl2 { set; private set; }
view XAML:
<ListBox Name="x:MyStuffListBox1" SelectedIndex="{Binding MyStuff1SelectedIndex}.... />
<ListBox Name="x:MyStuffListBox2" SelectedIndex="{Binding MyStuff2SelectedIndex}...../>
given that, I want my viewmodel to be able to have a command which could move items from one list box to another, w/ code such as the following:
public void MoveItemCommandExecute(...)
{
var sourceItem = MyStuff1ItemsControl.MagicGetItemExtensionMehod(MyStuff1SelectedIndex);
MyStuff1ItemsControl.MagicRemoveItemExtensionMethod(MyStuff开发者_运维技巧1SelectedIndex);
MyStuff2ItemsControl.MagicAddItemExtensionMethod(sourceItem);
}
so, basically, what would the binding XAML look like ? I am trying to set a property on the view model from the view...
thanks!
You'll want to rethink this approach. Typically, you would bind your two listboxes ItemsSource properties to two ObservableCollection<T>
properties on your view model, where T is the type of object in your list.
<ListBox x:Name="MyStuffListBox1" ItemsSource="{Binding MyList1}" SelectedItem="{Binding SelectedList1Item}" />
<ListBox x:Name="MyStuffListBox2" ItemsSource="{Binding MyList2}" SelectedItem="{Binding SelectedList2Item}" />
Note: I would use x:Name in your XAML, rather than the Name attribute.
public ObservableCollection<Thing> MyList1 { get; set; }
public ObservableCollection<Thing> MyList2 { get; set; }
// these properties should raise property changed events (INotifyPropertyChanged)
public Thing SelectedList1Item { get {...} set {...} }
public Thing SelectedList2Item { get {...} set {...} }
// constructor
public MyViewModel()
{
// instantiate and populate lists
this.MyList1 = new ObservableCollection(this.service.GetThings());
this.MyList2 = new ObservableCollection(this.service.GetThings());
}
You can then format what is displayed in the lists using DisplayMemberPath or defining an ItemTemplate on each list.
You can swap items between the lists by using the standard Collection methods on the ObservableCollection type - http://msdn.microsoft.com/en-us/library/ms668604.aspx
You shouldn't be implementing controls in your view model. That makes it a view, not a model of a view. The properties on your view model should be ObservableCollection<T>
, and you should be binding the ItemsSource
of items controls to those properties.
If you do this, your XAML might look like this:
<ListBox ItemsSource="{Binding List1}" SelectedItem="{Binding SelectedItem1, Mode=TwoWay}"/>
<ListBox ItemsSource="{Binding List2}" SelectedItem="{Binding SelectedItem2, Mode=TwoWay}"/>
<Button Command="{Binding MoveItemFromList1ToList2Command}">Move</Button>
List1
and List2
are of type ObservableCollection<T>
, SelectedItem1
and SelectedItem2
are of type T
(whatever type you've decided T
should be), and MoveItemFromList1ToList2Command
is a RoutedCommand
that has these two handlers defined:
public bool CanMoveItemFromList1ToList2
{
{ get { return SelectedItem1 != null; }
}
public void MoveItemFromList1ToList2()
{
List2.Add(SelectedItem1);
List1.Remove(SelectedItem1);
}
I'd have to test this code to be sure, but I don't think you need to bother with property-change notification in the MoveItemFromList1ToList2
method; when you remove the item from List1
, the ObservableCollection
will notify the ListBox
that the item's been removed, and the ListBox
will set SelectedItem
to null, updating SelectedItem1
in the view model. (And, of course, that will make the code break if you remove it from the first collection before adding it to the second.)
精彩评论