2010-04-29 13 views
8

Chcę powiązać wybrane elementy Listbox z tablicą. Ale .NET zgłasza wyjątek w czasie wykonywania.ListBox SelectedItems Binding

d.SetBinding(ListBox.SelectedItemsProperty, new Binding { Source = SomeArray }); 

Gdzie d to część ListBox z XAML.

Wyjątek:

Wybrana pozycja nie może być związany.

Dlaczego?

Odpowiedz

1

ListBox.SelectedItems jest tylko do odczytu. Czy zamiast tego chciałeś połączyć się z ListBox.SelectedItem?

+0

Nie mam kilka wybranych elementów i chcę, aby pokazać je w ListBox w stanie wybranym – Polaris

+1

Ponieważ własność jest tylko do odczytu, nie można go używać na co Cię chcieć. Jedyne, co mogę wymyślić, to ustawić indywidualne właściwości 'ListBoxItem.IsSelected'. Jeśli nalegasz na wiązanie, najłatwiejszą ścieżką byłoby utworzenie np. dołączone SelectedItems 'DependencyProperty' z niestandardową logiką w zmienionej właściwości obsługi zdarzenia. – wpfwannabe

1

Nie jestem pewien, czy dobrze rozumiem twoje pytanie, czy dokładny scenariusz - ale zakładając, że chcesz mieć jeden listbox "d", pokaż elementy, które zostały wybrane w innym polu listy "MyOtherListbox", po prostu musisz ustawić powiązanie w trybie "w jedną stronę" spowoduje wyświetlenie błędu.

Można zrobić coś takiego

d.SetBinding(ListBox.ItemsSourceProperty, new Binding { Source = MyOtherListbox.SelectedItems, Mode = BindingMode.OneWay}); 
+0

Muszę użyć czegoś takiego: d.SetBinding (ListBox.SelectedItemsProperty, new Binding {Source = SomeArray, Mode = OneWay}); Ale podnosi ten sam wyjątek. – Polaris

+1

Nie, nie można powiązać z SelectedItemsProperty, ponieważ ma on tylko accessor. myślę najbliżej można dostać się do to jeśli czytasz wątku ... http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/f0183ef3-ee0e-4de9 -86c7-73d2072baba7 –

+0

świetny wątek. Działa tak jak oczekuję. – Polaris

7

można subskrybować przypadku SelectionChanged w ListBox, aw obsługi synchronizacji zbiór wybranych pozycji.

W tym przykładzie Windows DataContext został ustawiony na siebie (this) w swoim konstruktorze. Można również łatwo wywołać warstwę logiczną (ViewModel, jeśli używasz MVVM) z obsługi zdarzenia.

w XAML:

<StackPanel> 

    <ListBox 
     ItemsSource="{Binding ListBoxItems}" 
     SelectionMode="Multiple" 
     SelectionChanged="ListBox_SelectionChanged"> 
    </ListBox> 

    <ItemsControl 
     ItemsSource="{Binding SelectedItems}"> 
    </ItemsControl> 

</StackPanel> 

I opóźnieniem kodu:

private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    foreach (string item in e.RemovedItems) 
    { 
     SelectedItems.Remove(item); 
    } 

    foreach (string item in e.AddedItems) 
    { 
     SelectedItems.Add(item); 
    } 
} 
+2

To wydaje się działać jako wiązanie OneWayToSource. Jeśli zmienię kolekcję SelectedItems, zmiany nie zostaną odzwierciedlone w polu listy. –

+1

@BogdanVerbenets Może ustawienie Mode na TwoWay i UpdateSourceTrigger na PropertyChanged będzie działać? Przy okazji, mamy to samo imię! : D –

+2

Rewizja jest zajętą, ponieważ sugerowanie użycia procedury obsługi zdarzeń w kodzie z tyłu do wywołania modelu widoku nie jest zgodne ze wzorcem MVVM. Jeśli nie masz nic przeciwko kodowi (i nie przeszkadza mi to, ale cokolwiek), użyj tego. Ale proszę, nie zanieczyszczaj modeli widoków przez wywoływanie ich z kodu z tyłu. – aaronburro

3

Jest to roztwór roboczy, jednak gdy wybór zmienia SelectedItemsProperty nie odświeżyć powiązań ...

można utworzyć niestandardową formantu zgodnie z poniższym opisem:

public class MyListBox: ListBox{ 

    public MyListBox() 
    { 
     this.SelectionChanged += (s,e)=>{ RefreshBindings(); }; 
    } 

    private void RefreshBindings() 
    { 
     BindingExpression be = 
      (BindingExpression) GetBindingExpression(
             SelectedItemsProperty); 
     if(be!=null){ 
       bd.UpdateTarget(); 
     } 
    } 

} 

lub w aplikacji można zdefiniować zdarzenia w każdym listbox jak pokazano poniżej ..

myListBox.SelectionChanged += (s,e) => { 
    BindingExpression be = 
     (BindingExpression) myListBox.GetBindingExpression(
             ListBox.SelectedItemsProperty); 
    if(be!=null){ 
     bd.UpdateTarget(); 
    } 
}; 
+0

dziękuję. dodałem obejście w mojej odpowiedzi – dovid

0

mój trick: w XAML, należy MultiBinding, siły wykonać konwerter w Count zmiany własności (warto!).

<MultiBinding Converter="{StaticResource SelectedRowsTotal }"> 
    <Binding Path="SelectedItems" ElementName="listBox1" /> 
    <Binding Path="SelectedItems.Count" ElementName="listBox1" /> 
</MultiBinding> 

Przelicznik:

public class SelectedRowsTotal : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
    { 
     var selecteds = values as IEnumerable; 

     if (selected == null) 
      return null; 

     return selecteds.Cast<SomeType>().Sum(x=> x.SomeProperty) = total; 
    } 

    object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 
    { 
     return null; 
    } 
}