All Blog Posts

Locking and Unlocking controls in a Silverlight LOB Application

Recently we were working on a Silverlight Line of Business application with a requirement that all data fields should be read only until the user clicks an Edit button. This was the requirement for all screens and there are quite a number of screens in the application. We thought about this for a bit and decided it would be most efficient to come up with a technique we could write once and apply across all screens.

This entry describes our solution. Our approach simply involves creating a method which accepts a control and a boolean parameter and then loops through all children controls of the passed control and sets the appropriate property based on the bool parameter (e.g. IsEnabled = false;). 

Here are the details.

Created a public static class that can be used by all screens in the system.

namespace FarReach.App.Helpers { public static class HelperFunctions { } }

Within this class we created public static methods that are called by the screens. There is one method for Lock and another for Unlock. Notice that these methods accept a control of type Panel, which means that in each screen we will wrap all of the controls to lock/unlock in a StackPanel.
public static void LockChildControls(Panel parentControl) { EditChildControls(parentControl, true); }
public static void UnlockChildControls(Panel parentControl) { EditChildControls(parentControl, false); }

Now the guts of things - the EditChildControls method. You will note that we loop through all child controls of the parent control which was passed in by the screen. We look for specific types of controls to Lock/Unlock and process them appropriately.

Note also that we are using Telerik Silverlight controls and add cases for those controls. Another item to note is that for some container controls like Grid, Border, and StackPanel, we call EditChildControls so that we can Lock/Unlock their children controls.
private static void EditChildControls(Panel parentControl, bool isLock) { foreach (var control in parentControl.Children) { switch (control.GetType().Name.ToLower()) { case "textbox": ((TextBox)control).IsReadOnly = isLock; break; case "checkbox": ((CheckBox)control).IsEnabled = !isLock; break; case "radmaskedtextinput": ((RadMaskedTextInput)control).IsReadOnly = isLock; break; case "radcombobox": ((RadComboBox)control).IsEnabled = !isLock; break; case "raddatepicker": ((RadDatePicker)control).IsReadOnly = isLock; break; case "radgridview": RadContextMenu.GetContextMenu((RadGridView)control).IsEnabled = !isLock; break; case "stackpanel": EditChildControls((StackPanel)control, isLock); break; case "grid": EditChildControls((Grid)control, isLock); break; case "border": EditChildControls((Border)control, isLock); break; } } }

private static void EditChildControls(Border parentControl, bool isLock) { if (parentControl.Child != null) { switch (parentControl.Child.GetType().Name.ToLower()) { case "stackpanel": EditChildControls((StackPanel) parentControl.Child, isLock); break; case "grid": EditChildControls((Grid) parentControl.Child, isLock); break; } } }

Now that we have all of this setup it is easy to implement from the screen. All we have to do is wrap all of our controls within a StackPanel and then call the Lock/Unlock function in code.
private void SetToViewMode() { btnEdit.Visibility = Visibility.Visible; btnSave.Visibility = Visibility.Collapsed; HelperFunctions.LockChildControls(stackOrgInfo); HelperFunctions.LockChildControls(stackBillingInfo); }
private void SetToEditMode() { btnEdit.Visibility = Visibility.Collapsed; btnSave.Visibility = Visibility.Visible; HelperFunctions.UnlockChildControls(stackOrgInfo); HelperFunctions.UnlockChildControls(stackBillingInfo); }

That's it! Now all of our screens can be locked and unlocked with ease. I hope you find this tip useful. I would be happy to hear you thoughts or techniques you may have implemented regarding this type of requirement.