In 2006 I developed a small piece of code in order to use a declarative control state handling in WinForm Applications. Three years later (2009) I thought declarative control state handling should be standard in Silverlight – but I failed. So I decided to migrate that piece of code to the new Silverlight plattform.
Imagine you have a really big application – How would you ensure the control state of every control? In former times this had been done in endless “if – then – else” horror code blocks. That time is history now. A better solution is to use a configuration file and define rules to enable/disable and visible/collapse controls.
Before you read: Here’s an example application.
Here’s the configuration file for the example:
<add key="txtAlwaysVisible" state="True"/>
<add key="txtVisibleHidden" check="IsVisible" changeVisibility="true"/>
<add key="radEnabled" check="IsRadioButtonEnabled" />
<add key="radAdmin" roles="Admin" />
<add key="radEditor" roles="Editor" />
<add key="radBoth" roles="Admin, Editor" />
As you can see the uipConfig file is devided in Sections. A Section is a logical component that contains controls. In our example the Section is defined as the Silverlight Page. In the every section all controls that are interessting for us have a key that is used to define the rules.
Here are the allowed attributes:
|state||Can be set to true / false or can be left empty. If a state has been set, all other checks will be ignored.|
|roles||It’s a comma separated list with roles, the current principal must belong to. If the current principal does not belong to the role, the control will be disabled.|
|check||It’s a comma separated list with check routines that tells the State Manager if the control has to be disabled or enabled. Such a check routine can be implemented in a controller class or within the Page itself – and it’s more or less a property that returns true or false.|
|changeVisibility||This flag defines, if the visibility of the control shall be changed. If this flag has not been defined, the enabled/disabled state is used.|
All you have to do is to make the ControlStateExtender available to your silverlight application. Therefore you have to place the reference in your UserControl element of your page.
After that you can add the attribute sate:ControlStateExtender.ControlKey to any of your controls.
<TextBlock state:ControlStateExtender.ControlKey="Page, txtVisibleHidden" …
The first word defines the section, the second the key of the control within the section. Now – what do you have to change in code?
That’s pretty easy and also straight forward. You have to add a private readonly ControlStateExtender to your page. This object handles the state of your controls. Furthermore you have to initialize the ControlStateExtender object after the call of InitializeComponent().
public partial class Page : UserControl
private readonly ControlStateExtender cse = ControlStateExtender.GetExtender("Page");
/// <summary> Constructor </summary>
Now you can define the control state rules in your application.
#region Control State Rules
public bool IsVisible
private bool disableRadioButtons = false;
public bool IsRadioButtonEnabled
The control state rules (business rules) will be invoked by the ControlStateManager when the Refresh() method is called. So, any time, you expect the control states to be changed you have to call the Refresh() method of the ControlStateManager to re-validate the rules.
#region Handler that refrehes the control state
private void OnRadChecked(object sender, RoutedEventArgs e)
private void OnEnableDisableClick(object sender, RoutedEventArgs e)
disableRadioButtons = !disableRadioButtons;
private void SetAsEditor(object sender, RoutedEventArgs e)
CurrentPrincipal.Principal = new MyEditorPrincipal();
private void SetAsAdmin(object sender, RoutedEventArgs e)
CurrentPrincipal.Principal = new MyAdminPrincipal();
If you write your own application, don’t forget to embedd the uiStates.config in your silverlight application. To to this, set the Build Acction to “Embedded Resource” for the uiStates.config.
Last but not least I want to say thanks for the ReaderWriterLock Re-Implementation of Vance Morrison. As an additional goodie the code uses a Cache Implementation to store the method, properties and config sections. This Cache Implementation is not dependend on the ControlStateExtender and can be used everywhere in your application.
Here’s the complete source code of the ControlStateExtender example application.
Hope you enjoy it.