Tak, że masz ViewModel o następujących właściwościach:
public ObservableCollection<string> AllItems { get; private set; }
public ObservableCollection<string> SelectedItems { get; private set; }
Można by zacząć od wiążący swoją kolekcję AllItems do ListBoks:
<ListBox x:Name="MyListBox" ItemsSource="{Binding AllItems}" SelectionMode="Multiple" />
Problem polega na tym, że właściwość SelectedItems w ListBox nie jest DependencyProperty. Jest to bardzo złe, ponieważ nie można powiązać go z czymś w swoim ViewModelu.
Pierwsze podejście jest po prostu umieścić tę logikę w opóźnieniem kodu, aby dostosować ViewModel:
public MainPage()
{
InitializeComponent();
MyListBox.SelectionChanged += ListBoxSelectionChanged;
}
private static void ListBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var listBox = sender as ListBox;
if(listBox == null) return;
var viewModel = listBox.DataContext as MainVM;
if(viewModel == null) return;
viewModel.SelectedItems.Clear();
foreach (string item in listBox.SelectedItems)
{
viewModel.SelectedItems.Add(item);
}
}
Podejście to będzie działać, ale to jest naprawdę brzydka. Moim preferowanym podejściem jest wyodrębnienie tego zachowania w "Attached Behavior". Jeśli to zrobisz, możesz całkowicie wyeliminować swój kod z tyłu i ustawić go w XAML. Bonus jest, że to „Przydzielony Zachowanie” jest teraz ponownie wykorzystywane w każdym ListBox:
<ListBox ItemsSource="{Binding AllItems}" Demo:SelectedItems.Items="{Binding SelectedItems}" SelectionMode="Multiple" />
A oto kod dla podłączonej Zachowanie:
public static class SelectedItems
{
private static readonly DependencyProperty SelectedItemsBehaviorProperty =
DependencyProperty.RegisterAttached(
"SelectedItemsBehavior",
typeof(SelectedItemsBehavior),
typeof(ListBox),
null);
public static readonly DependencyProperty ItemsProperty = DependencyProperty.RegisterAttached(
"Items",
typeof(IList),
typeof(SelectedItems),
new PropertyMetadata(null, ItemsPropertyChanged));
public static void SetItems(ListBox listBox, IList list) { listBox.SetValue(ItemsProperty, list); }
public static IList GetItems(ListBox listBox) { return listBox.GetValue(ItemsProperty) as IList; }
private static void ItemsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var target = d as ListBox;
if (target != null)
{
GetOrCreateBehavior(target, e.NewValue as IList);
}
}
private static SelectedItemsBehavior GetOrCreateBehavior(ListBox target, IList list)
{
var behavior = target.GetValue(SelectedItemsBehaviorProperty) as SelectedItemsBehavior;
if (behavior == null)
{
behavior = new SelectedItemsBehavior(target, list);
target.SetValue(SelectedItemsBehaviorProperty, behavior);
}
return behavior;
}
}
public class SelectedItemsBehavior
{
private readonly ListBox _listBox;
private readonly IList _boundList;
public SelectedItemsBehavior(ListBox listBox, IList boundList)
{
_boundList = boundList;
_listBox = listBox;
_listBox.SelectionChanged += OnSelectionChanged;
}
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
_boundList.Clear();
foreach (var item in _listBox.SelectedItems)
{
_boundList.Add(item);
}
}
}
to nie działa z SL3, czy to działało dla kogoś innego? – Neil
to nie działa w ogóle, nie tylko dlatego, że klasa powinna być statyczna, wybrane pozycje zawsze mają wartość NULL. – msfanboy
Działa to w SL3, SL4 i WPF. Używam tej metody przez cały czas. Tak, klasa przechowująca przywiązane zachowanie powinna być statyczna. Jest to część wzorca "Attached Behaviour" w SL i WPF. –