Skip Navigation LinksHome / Articles / View Article

Tip: Easy/Reusable selection with ISelectable and SelectionManager

+ Add to SilverlightShow Favorites
2 comments   /   posted by Denislav Savkov on Aug 01, 2008
(0 votes)
Categories: Samples , Tips and Tricks

Introduction

The need of selection is a pretty common thing. That made us think of a way to generalize the task and create a reusable class that can be used in more than one scenario. We put together a simple helper class that lets you handle selection easily.  The responsibilities of the class are:

  • to keep only one item selected;
  • to give you the index of the selected item;
  • possibly to return a handle to the selected item

You can use the SelectionManager on any ObservableCollection of ISelectable objects. In fact you could use it on non-UI objects if you need to have one object in one state and the rest in another. ISelecatble is a simple interface that has three parts:

  • Selected event that should be raised when an object transits to the Selected state
  • Select/Deselect methods that should set the state of the object to selected or deselected
public interface ISelectable
{
    event EventHandler Selected;
    void Select();
    void Deselect();
}

After you define these three parts in your class you only need to pass the collection of objects to the SelectionManager and hook to the SelectionChange event.

Items are selected on MouseOver.

 Download source code.

Implementation

The SelectionManager keeps a reference to an ObservableCollection outside the class and it hooks to the Selected event of each item provided by ISelectable.

private ObservableCollection items;
 
public void HookToObservableCollection( ObservableCollection items )
{   ...
    this.items = items;
    items.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(
                                                                                            CollectionChanged );
    foreach ( ISelectable current in this.items )
    {
        current.Selected += new EventHandler( OnItemSelected );
    }
}

The SelectionManager handles changes in the collection automatically.

void CollectionChanged( object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e )
{
    if ( e.Action == NotifyCollectionChangedAction.Remove || e.Action == NotifyCollectionChangedAction.Replace )
    {
        foreach ( ISelectable newItem in e.OldItems )
        {
            newItem.Selected -= new EventHandler( OnItemSelected );
        }
    }
    if ( e.Action == NotifyCollectionChangedAction.Add || e.Action == NotifyCollectionChangedAction.Replace )
        foreach ( ISelectable newItem in e.NewItems )
        {
            newItem.Selected += new EventHandler( OnItemSelected );
        }
}

When an item is selected the SelectionManager deselects the last selected item. and fires the SelectionChange event.

public void OnItemSelected( object sender, EventArgs e )
{
    _next = this.items.IndexOf( sender as ISelectable );
    if ( _lastSelected != _next )
        this.items[ _lastSelected ].Deselect();
    _lastSelected = _next;
    if ( this.SelectionChange != null )
        this.SelectionChange( sender, new SelectionChangedEventArgs( _lastSelected ) );
}

To deliver the index of the selected item SelectionChange uses SelectionChangedEventArgs that contain an int.

public class SelectionChangedEventArgs : EventArgs
{
    public SelectionChangedEventArgs( int indexOfSelectedItem )
    {
        this.selectedItemIndex = indexOfSelectedItem;
    }
    public int selectedItemIndex;
}

Conclusion

In our example we demonstrate the selection in two ways. Inside the ISelectable control with the blue border and outside in the application with the grey "x"-box. Check out our source for more details.

Share


Comments

Comments RSS RSS
  • RE: Tip: Easy/Reusable selection with ISelectable and SelectionManager  

    posted by Justin-Josef Angel [MSFT] on Aug 26, 2008 10:46

    Very nice article.

    One thing though, if we take this sample towards a real world application, we'd probably want something a bit less intrusive.
    Implementing interfaces on controls provided in the framework is hardly a good option since it requires us to subset all controls in the framework.
    Sub-setting doesn't work as well as we'd think it does because of stuff like missing blend support (the controls icons in blend will always create framework controls and not our subset controls). 

    IMO, A far less intrusive mechanism would have been to catch all user interactions (hookup to all keyboard and mouse events on the Application.RootVisual) and than query the FocusManager to get the currently focused element. 

     

     

  • RE: Tip: Easy/Reusable selection with ISelectable and SelectionManager  

    posted by Denislav Savkov on Aug 28, 2008 08:16

    Hi Justin and thank you for your comment,

    a less intrusive SelectionManager is possible if we hookup to some of the FrameworkElement events. However this won't work  very well for all FrameworkElements. If we hookup to MouseButtonDown for instance Buttons won't be selectable. If we hookup to GotFocus some elements that don't receive focus like Canvas won't be selectable.

    If it is possible would you explain in more detail your idea with the FocusManager. 

Add Comment

 
 

   
  
  
   
Please add 1 and 2 and type the answer here:

Join the free SilverlightShow webcast 'Running Silverlight Outside the Browser and with Elevated Trust'. Sept 7th, 8 am - 9 am PDT.
In this live session Chris Anderson will cover configuring and debugging OOB mode, toast notifications, elevated trust, direct file access and much more.
Learn more | Register | See more webinars (hide this)