So nähern, übernehmen Sie eine Ansichtsmodell mit den folgenden Eigenschaften haben:
public ObservableCollection<string> AllItems { get; private set; }
public ObservableCollection<string> SelectedItems { get; private set; }
Sie würden beginnen, indem Sie Ihre AllItems Sammlung Bindung an die ListBox:
<ListBox x:Name="MyListBox" ItemsSource="{Binding AllItems}" SelectionMode="Multiple" />
Das Problem besteht darin, dass die SelectedItems-Eigenschaft in ListBox keine DependencyProperty ist. Das ist ziemlich schlecht, da Sie es nicht an etwas in Ihrem ViewModel binden können.
Der erste Ansatz ist nur in dem Code-Behind diese Logik zu setzen, das Ansichtsmodell zu optimieren:
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);
}
}
Dieser Ansatz funktioniert, aber es ist wirklich hässlich. Mein bevorzugter Ansatz besteht darin, dieses Verhalten in ein "Attached Behavior" zu extrahieren. Wenn Sie das tun, können Sie Ihren Code-Behind komplett beseitigen und im XAML einrichten. Der Bonus ist, dass diese "Befestigt Behavior" ist nun wieder verwendbar in jeder List-Box:
<ListBox ItemsSource="{Binding AllItems}" Demo:SelectedItems.Items="{Binding SelectedItems}" SelectionMode="Multiple" />
Und hier ist der Code für das angebaute Verhalten:
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);
}
}
}
das funktioniert nicht mit SL3, hat das für jemand anderes funktioniert? – Neil
das funktioniert überhaupt nicht, nicht nur weil die Klasse statisch sein sollte die ausgewählten Items sind immer Null. – msfanboy
Dies funktioniert in SL3, SL4 und WPF. Ich benutze diese Methode die ganze Zeit. Ja, die Klasse mit dem angehängten Verhalten sollte statisch sein. Es ist Teil des "Attached Behavior" -Musters in SL und WPF. –