locked
Selectors and attached behaviours RRS feed

  • Question

  • Hi,
    I have a a data-binding on an ObservableCollection to a ListBox through data templates. All works fine in that I have several listboxes populated with data that is styled to look like an winforms ListView in tile mode.

    My problem is that I need one item to be selected only through the complete form, even though multiple ListBoxes are involved. I'm using attached behaviours to capture item selection changes ok, but I'm having to do a lot of visualtree hunting to unselect items in other listboxes.

    Is there a better way to achieve this behaviour? Maybe a static SelectedNode item?

    Any ideas appreciated.
    Ciaran
    Thursday, November 12, 2009 7:32 PM

Answers

  • I managed a more general solution to this problem than I initially planed. The solution allowed me to define a type of 'global' selection list that had boundaries
    across container controls.
    I create a dependency property in a GlobalGroupBehaviour class like this:

           public static readonly DependencyProperty GlobalGroupProperty = 
                DependencyProperty.RegisterAttached(
                                                "GlobalGroup",
                                                typeof(string),
                                                typeof(GlobalGroupBehaviour),
                                                new UIPropertyMetadata("", OnGlobalGroupMembershipPropertyChanged)
                                            );
    and then in the XAML datatemplate I can do something like this:


        <DataTemplate x:Key="ProjectItemTemplate" DataType="{x:Type pt:ProjectTemplateElement}" >
            <Border x:Name="ProjectItem" HorizontalAlignment="Center" VerticalAlignment="Center" Focusable="True" Width="60" Height="76">
               <Image Source="{Binding Path=TemplateIcon}" util:GlobalGroupBehaviour.GlobalGroup="someGroupName" />
             </Border>
        </DataTemplate>

    I also keep a mapping of the UIElement and the associated selection group it wants to belong to (inside the static behaviour class)

            private static Dictionary<string, WeakReference> _selectedItems = new Dictionary<string, WeakReference>();
    
    In the 'OnGlobalGroupMembershipPropertyChanged' handler, I can just add a new handler to the element-selected event. From then on it's easy - when a listboxitem is selected (or any other container item), the event will trigger and the behavior class can iterate through all items in the list and make sure they aren't selected using the IsSelected property.
    This solution means that several listboxes on the same form can be part of a global selection group, and even have multiple groups on the same form.
    Hope this helps someone else.
    Ciaran.



    • Edited by Zoodazzle Saturday, November 14, 2009 12:02 AM formatting
    • Marked as answer by Zhi-Xin Ye Thursday, November 19, 2009 9:19 AM
    Saturday, November 14, 2009 12:00 AM

All replies

  • You could use a single service (or just a static private class member + event) within the Behavior that provides the selected node.  When your behavior goes to change it, the other behaviors could unselect their appropriate list box on the fly.

    I would highly recommend using the WeakEvent pattern for this, though.  You'll most likely want to have some form of event (selection changed) on a static object, and this will help protect you from memory leaks in this situation.


    Reed Copsey, Jr. - http://reedcopsey.com
    Thursday, November 12, 2009 7:50 PM
  • I managed a more general solution to this problem than I initially planed. The solution allowed me to define a type of 'global' selection list that had boundaries
    across container controls.
    I create a dependency property in a GlobalGroupBehaviour class like this:

           public static readonly DependencyProperty GlobalGroupProperty = 
                DependencyProperty.RegisterAttached(
                                                "GlobalGroup",
                                                typeof(string),
                                                typeof(GlobalGroupBehaviour),
                                                new UIPropertyMetadata("", OnGlobalGroupMembershipPropertyChanged)
                                            );
    and then in the XAML datatemplate I can do something like this:


        <DataTemplate x:Key="ProjectItemTemplate" DataType="{x:Type pt:ProjectTemplateElement}" >
            <Border x:Name="ProjectItem" HorizontalAlignment="Center" VerticalAlignment="Center" Focusable="True" Width="60" Height="76">
               <Image Source="{Binding Path=TemplateIcon}" util:GlobalGroupBehaviour.GlobalGroup="someGroupName" />
             </Border>
        </DataTemplate>

    I also keep a mapping of the UIElement and the associated selection group it wants to belong to (inside the static behaviour class)

            private static Dictionary<string, WeakReference> _selectedItems = new Dictionary<string, WeakReference>();
    
    In the 'OnGlobalGroupMembershipPropertyChanged' handler, I can just add a new handler to the element-selected event. From then on it's easy - when a listboxitem is selected (or any other container item), the event will trigger and the behavior class can iterate through all items in the list and make sure they aren't selected using the IsSelected property.
    This solution means that several listboxes on the same form can be part of a global selection group, and even have multiple groups on the same form.
    Hope this helps someone else.
    Ciaran.



    • Edited by Zoodazzle Saturday, November 14, 2009 12:02 AM formatting
    • Marked as answer by Zhi-Xin Ye Thursday, November 19, 2009 9:19 AM
    Saturday, November 14, 2009 12:00 AM
  • Hi,

    great solution. I'd like to adapt it a bit and add it to my collection in http://wpfglue.wordpress.com . Do you mind? And would you like to post a permanent link so I can give you credit?

    Anyway, five Sticky Stars from me...
    http://wpfglue.wordpress.com
    Saturday, November 14, 2009 6:03 AM
  • Hi, I don't mind at all. Thanks for the comments and glad I could be of help.
    Ciaran.
    Saturday, November 14, 2009 10:07 AM