If I use an attached property with two controls in the same window, it doesn't work

62 views Asked by At

I have this attached property:

public class ListBoxSelectedItemsAttachedProperty
    {
        #region SelectedItems
        private static ListBox list;

        public static readonly DependencyProperty SelectedItemsProperty =
        DependencyProperty.RegisterAttached("SelectedItems", typeof(IList),
        typeof(ListBoxSelectedItemsAttachedProperty),
        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)
        {
            ListBox listBox = (ListBox)d;
            list = listBox;
            listBox.SelectionChanged += listBox_SelectionChanged;
            listBox.Unloaded += listBox_Unloaded;
        }

        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);
        }




        private static void listBox_Unloaded(object sender, RoutedEventArgs e)
        {
            ListBox listBox = sender as ListBox;
            listBox.SelectionChanged -= listBox_SelectionChanged;
            listBox.Unloaded -= listBox_Unloaded;
        }
        #endregion
    }

And I have two listbox in my window, that use this attached property, in this way:

<ListBox HorizontalAlignment="Left" Margin="5,0,5,0" Name="lsbGenerosAsignados" VerticalAlignment="Stretch" Width="Auto" MinWidth="130" Grid.Column="2" Grid.Row="1"
                 SelectionMode="Extended"
                 ItemsSource="{Binding Collection1InViewModel}"
                 DisplayMemberPath="Name"
                 Behaviors:ListBoxSelectedItemsAttachedProperty.SelectedItems="{Binding Property1InViewModel}"> 


    <ListBox HorizontalAlignment="Left" Margin="5,0,5,0" Name="lsbGenerosAsignados" VerticalAlignment="Stretch" Width="Auto" MinWidth="130" Grid.Column="2" Grid.Row="1"
                 SelectionMode="Extended"
                 ItemsSource="{Binding Collection2InViewModel}"
                 DisplayMemberPath="Name"
                 Behaviors:ListBoxSelectedItemsAttachedProperty.SelectedItems="{Binding Property2InViewModel}">

However, the view model is not notify when the selection changes in the first listBox. If I delete de attached property from the second listBox, then it works as expected.

How I could use this attached property with the two listoBox and notify to the view model properties?

Thanks.

1

There are 1 answers

0
sTrenat On BEST ANSWER

this doesn't work because you set global

private static ListBox list;

when you have 2 lists, the second one will override your field 'list' so it wont work. Try this:

public class ListBoxSelectedItemsAttachedProperty
{
    #region SelectedItems

    public static readonly DependencyProperty SelectedItemsProperty; 

    static ListBoxSelectedItemsAttachedProperty()
    {
        FrameworkPropertyMetadata MetaData = new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault
                                             , new PropertyChangedCallback(OnSelectedItemsChanged));

        SelectedItemsProperty =  DependencyProperty.RegisterAttached("SelectedItems", typeof(IList),
                                 typeof(ListBoxSelectedItemsAttachedProperty),
                                 MetaData);
    }

    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)
    {
        ListBox listBox = (ListBox)d;
        listBox.SelectionChanged +=  listBox_SelectionChanged;
        listBox.Unloaded += listBox_Unloaded;
    }

    private static void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var list = (ListBox)sender;
        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);
    }




    private static void listBox_Unloaded(object sender, RoutedEventArgs e)
    {
        ListBox listBox = sender as ListBox;
        listBox.SelectionChanged -= listBox_SelectionChanged;
        listBox.Unloaded -= listBox_Unloaded;
    }
    #endregion
}