Telerik Product and Version
|
Q1 2015 and up
|
Supported Browsers and Platforms
|
.NET 4.0/4.5
|
Components/Widgets used (JS frameworks, etc.)
|
|
PROJECT DESCRIPTION
Telerik quietly added a feature to their WPF
RadListBox in their 1Q 2015 update that is coincidentally a feature I needed in a current project. The feature is the ability to bind the selected items in the
RadListBox.
The out of the box
ListBox as well as Telerik’s
RadListBox both have a
SelectedItems property. Unfortunately, for whatever reason neither support binding to the property.
My current project is a WPF Prism application with specialized module loading. The application will live on a Terminal Server with all modules installed, so the need is to load the modules based on the logged-on user. The objects in play are the user and module. The user contains a collection of the modules it is assigned.
This use case can be approached in different ways. The approach I chose involves using two list boxes. The left list box contains a list of the users defined for the system. The right list contains a list of all the modules. The selections shown in the modules list box are changed as the currently selected user is changed.
Example UI:
http://i.imgur.com/RvTXPvJ.jpg?1
The demo project addresses the problem in a simplified manner. There is no dependency on Prism or any other libraries other than the latest Telerik Devcraft tools for WPF; specifically, the
RadListBox. Features in my solution have been scaled down to focus on the multiple selection binding.
The implementation of the user and module objects are pretty straightforward with one exception. The modules contained in the user object need to be managed by an
ObservableCollection<T>, or a collection that implements
INotifyCollectionChanged and
INotifyPropertyChanged.
public
sealed
class
AppUser
{
public
AppUser()
{
Modules =
new
ObservableCollection<AppModule>();
}
public
string
DisplayName {
get
;
set
; }
public
string
UserName {
get
;
set
; }
public
ObservableCollection<AppModule> Modules {
get
;
private
set
; }
public
override
string
ToString()
{
return
DisplayName ?? UserName ??
"(No Name)"
;
}
}
You might think that you could simply bind to the
SelectedItems and call it a day. Unfortunately, that doesn’t work. Telerik decided to keep the behavior of the out of the box list box for that property. Instead they implemented an attached behavior.
<!-- cannot bind to the selected items this way -->
<
telerik:RadListBox
Grid.Column
=
"1"
x:Name
=
"ModulesListBox"
ItemsSource
=
"{Binding Modules}"
SelectedItems
=
"{Binding SelectedUser.Modules}"
SelectionMode
=
"Multiple"
/>
The behavior we want is available in the
ListBoxSelectedItemsBehavior. Specifically, we use the
SelectedItemsSource property. That will give us the selection behavior we want.
<
telerik:RadListBox
Grid.Column
=
"1"
x:Name
=
"ModulesListBox"
ItemsSource
=
"{Binding Modules}"
telerik:ListBoxSelectedItemsBehavior.SelectedItemsSource
=
"{Binding SelectedUser.Modules}"
SelectionMode
=
"Multiple"
/>
The modules assigned to the user will follow in the module’s list box as we change the selection in the user’s list box with the
ListBoxSelectedItemsBehavior in place.
This new behavior fills a gap in functionality present in the
RadListBox and it’s especially valuable in keeping implementation details from leaking into your view in an MVVM architecture. It seems like such a small thing, but features like this go a long way in making 3rd party tooling valuable within my organization.