0

I'm having really hard time trying to make listbox multiselection bindable, basically the same as this article : http://blogs.microsoft.co.il/miziel/2014/05/02/wpf-binding-listbox-selecteditems-attached-property-vs-style/

This is my class for the listbox :

public partial class ListBoxMultipleSelection : UserControl
{
    public ListBoxMultipleSelection()
    {
        InitializeComponent();
        this.DataContext = this;
    }

    public static readonly DependencyProperty ItemSourceProperty =
    DependencyProperty.Register("ItemSource", typeof(ObservableCollection<string>), typeof(ListBoxMultipleSelection), new PropertyMetadata(new ObservableCollection<string>()));
    public ObservableCollection<string> ItemSource
    {
        get { return (ObservableCollection<string>)this.GetValue(ItemSourceProperty); }
        set { this.SetValue(ItemSourceProperty, value); }
    }

    private static ListBox list;
    private static bool _isRegisteredSelectionChanged = false;

    ///
    /// SelectedItems Attached Dependency Property
    ///
    public static readonly DependencyProperty SelectedItemsProperty =
    DependencyProperty.RegisterAttached("SelectedItems", typeof(IList),
    typeof(ListBoxMultipleSelection),
    new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
    new PropertyChangedCallback(OnSelectedItemsChanged)));

    public static IList GetSelectedItems(DependencyObject d)
    {
        return (IList)d.GetValue(SelectedItemsProperty);
    }

    public static void SetSelectedItems(DependencyObject d, IList value)
    {
        d.SetValue(SelectedItemsProperty, value);
    }

    private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (!_isRegisteredSelectionChanged)
        {
            var listBox = (ListBox)d;
            list = listBox;
            listBox.SelectionChanged += listBox_SelectionChanged;
            _isRegisteredSelectionChanged = true;
        }
    }

    private static void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        IEnumerable listBoxSelectedItems = list.SelectedItems;
        IList ModelSelectedItems = GetSelectedItems(list);
        ModelSelectedItems.Clear();
        if (list.SelectedItems != null)
        {
            foreach (var item in list.SelectedItems) 
                ModelSelectedItems.Add(item);
        }
        SetSelectedItems(list, ModelSelectedItems);
    }
}

And the XAML for the usercontrol/listbox :

<Grid>
    <ListBox SelectionMode="Multiple"
             local:ListBoxMultipleSelection.SelectedItems="{Binding DataContext.SelectedItems}" 
             ItemsSource="{Binding DataContext.ItemSource, ElementName=MultiListBox, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>

The problem is "listBox_SelectionChanged" is never fired and so nothing is updated correctly. Any idea ?

Thank you

lecloneur
  • 424
  • 5
  • 20
  • 1
    That blog is crap! Do not use static members (`list` and `_isRegisteredSelectionChanged`) to keep track of the ListBox control where you attach a SelectionChanged hander. In the SelectionChanged handler you can get the ListBox control by casting the `sender` argument. An easier solution may even be to create a derived ListBox with a bindable SelectedItems property, as shown here: http://stackoverflow.com/q/11142976/1136211 – Clemens May 15 '16 at 07:46
  • thanks but I'm stuck on this for several days now, pain in the ass just to make that simple listbox where I could just bind SelectedItems in two ways like I would do for all other controls... – lecloneur May 15 '16 at 08:11
  • It's not clear why you want to do that at all. Better have an IsSelected property on your data item, as suggested by the accepted answer on the question I've linked. – Clemens May 15 '16 at 08:30
  • What I'm trying to achieve is having a listbox where I can load filenames and select multiple. Then at some point I want to load a list of "already'' selected items. Because some data loaded to the list box could be SelectedItems, or just ItemSources. Hope I'm clear... I'm still beginner with WPF and this one is difficult... – lecloneur May 15 '16 at 08:33
  • Also, in my case I don't have data items, everything will be loaded at runtime. So I'm now working only with dependency properties which are bound to usercontrols. – lecloneur May 15 '16 at 08:34
  • 1
    Create a view model with an item class that represents a file's name and selected state by two properties. Make sure the item class implements INotifyPropertyChanged to notify about changed property values. Then bind the ListBox's ItemsSource to an ObservableCollection of the item class. In a ListBoxItem Style (e.g. passed by the ListBox's ItemContainerStyle) bind the ListBoxItem's IsSelected property to the item's selected property. – Clemens May 15 '16 at 08:43
  • Smells like a binding error to me. Shouldn't the `SelectedItems` binding resemble the `ItemsSource` binding (i.e. have the `ElementName=MultiListBox` specified)? Could you look in the output window for any binding error messages? – Grx70 May 15 '16 at 08:58
  • @Clemens is it possible to just create two observablecollection one for FileName, the other for IsSelected and bound both to the listbox ? – lecloneur May 15 '16 at 10:41
  • Somehow everything is possible, but here it wouldn't make sense. – Clemens May 15 '16 at 12:25
  • Ok I have it working now with thanks to your post here : http://stackoverflow.com/questions/13611113/how-to-bind-listboxitem-isselected-to-boolean-data-property – lecloneur May 15 '16 at 13:58

0 Answers0