1

Here is the source code from my View.

<ListView SelectionMode="Multiple"
    ItemsSource="{Binding Items, Mode=OneWay}"
    SelectedItems="{Binding SelectedItems}">
        <ListView.ItemTemplate>
             <DataTemplate>
                 <Grid Height="55" Margin="-3,0,-3,0">
                     <TextBlock Text="{Binding Name}"/>
                 </Grid>
             </DataTemplate>
        </ListView.ItemTemplate>
</ListView>

I've tried to bind the SelectedItems-Property to my ViewModel. Source code:

    ObservableCollection<string> _selectedItems = new ObservableCollection<string>();
    public ObservableCollection<string> SelectedItems 
    {
        get { return _selectedItems; }
        set
        {
            _selectedItems = value;
            ***... 
            need to do some operaions here ... 
            ...*** 
            OnPropertyChanged("SelectedItems");
        }
    }

I need to do some operations within the SelectedItems-Property(ViewModel). How can I get there?

C8H10N4O2
  • 18,312
  • 8
  • 98
  • 134
ManDani
  • 182
  • 4
  • 16
  • That's not so important, because the source-code I've posted is not the complete (not the real one). In reality SelectedItems isn't just an ObservableCollection of string, but an collection of certain objects. I need to get those objects. Even when you set a Breakpoint whithin the setter, you can't stop the program. – ManDani Nov 05 '15 at 14:28
  • Oh I see. So your problem is that the binding doesn't seem to be working? That's not completely clear from your question. I presume you've implemented INotifyPropertyChanged (it looks like it)? – Bob Tway Nov 05 '15 at 14:30
  • Ah, it looks like SelectedItems is one way - you can't set it from inside the XAML. Tomtom's answer should help you. – Bob Tway Nov 05 '15 at 14:33

1 Answers1

4

We solved it with an attached property which looks like:

public class MultiSelectorExtension
{
    public static readonly DependencyProperty SelectedItemsProperty =
        DependencyProperty.RegisterAttached("SelectedItems", typeof(INotifyCollectionChanged), typeof(MultiSelectorExtension),
        new PropertyMetadata(default(INotifyCollectionChanged), OnSelectedItemsChanged));

    public static void SetSelectedItems(DependencyObject element, INotifyCollectionChanged value)
    {
        element.SetValue(SelectedItemsProperty, value);
    }

    public static INotifyCollectionChanged GetSelectedItems(DependencyObject element)
    {
        return (INotifyCollectionChanged)element.GetValue(SelectedItemsProperty);
    }

    private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        MultiSelector multiSelectorControl = d as MultiSelector;

        NotifyCollectionChangedEventHandler handler = (sender,
            args) =>
        {
            if (multiSelectorControl != null)
            {
                IList listSelectedItems = multiSelectorControl.SelectedItems;
                if (args.OldItems != null)
                {
                    foreach (var item in args.OldItems)
                    {
                        if (listSelectedItems.Contains(item))
                        {
                            listSelectedItems.Remove(item);
                        }
                    }
                }

                if (args.NewItems != null)
                {
                    foreach (var item in args.NewItems)
                    {
                        if (!listSelectedItems.Contains(item))
                        {
                            listSelectedItems.Add(item);
                        }
                    }
                }
            }
        };

        if (e.OldValue == null && multiSelectorControl != null)
        {
            multiSelectorControl.SelectionChanged += OnSelectionChanged;
        }

        if (e.OldValue is INotifyCollectionChanged)
        {
            (e.OldValue as INotifyCollectionChanged).CollectionChanged -= handler;
        }

        if (e.NewValue is INotifyCollectionChanged)
        {
            (e.NewValue as INotifyCollectionChanged).CollectionChanged += handler;
        }

    }

    private static void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        DependencyObject d = sender as DependencyObject;

        if (GetSelectionChangedInProgress(d))
            return;

        // Internal Flag to avoid infinite loop 
        SetSelectionChangedInProgress(d, true);

        dynamic selectedItems = GetSelectedItems(d);

        try
        {
            foreach (var item in e.RemovedItems.Cast<dynamic>().Where(item => selectedItems.Contains(item)))
            {
                selectedItems.Remove(item);
            }
        }
        catch (Exception)
        {

        }

        try
        {
            foreach (var item in e.AddedItems.Cast<dynamic>().Where(item => !selectedItems.Contains(item)))
            {
                selectedItems.Add(item);
            }
        }
        catch (Exception)
        {
        }


        SetSelectionChangedInProgress(d, false);
    }


    private static readonly DependencyProperty SelectionChangedInProgressProperty =
        DependencyProperty.RegisterAttached("SelectionChangedInProgress", typeof(bool), typeof(MultiSelectorExtension), new PropertyMetadata(default(bool)));

    private static void SetSelectionChangedInProgress(DependencyObject element,
        bool value)
    {
        element.SetValue(SelectionChangedInProgressProperty, value);
    }

    private static bool GetSelectionChangedInProgress(DependencyObject element)
    {
        return (bool)element.GetValue(SelectionChangedInProgressProperty);
    }
}

And our usage at a ListView looks like:

AttachedProperties:MultiSelectorExtension.SelectedItems="{Binding SelectedPersonss, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Parisa
  • 196
  • 2
  • 11
Tomtom
  • 9,087
  • 7
  • 52
  • 95
  • Thank you - that works! If I debug my program, I see that the SelectedItems-Property has all selected Items from the ListView. Is there a way to raise an event, if the user select or unselect an Item. I need to handle the change of my ListView-selection within my ViewModel. As I mention, If is set a breakpoint within my setter the program doesn't stop there. – ManDani Nov 05 '15 at 14:51
  • if this answer is the answer to your solution mark it as accepted as for other doubts and queries ask another question!! – Vivek Saurav Nov 06 '15 at 08:58