Introduction
Many times, we want to apply read only style to some of WPF controls such as TextBox
, CheckBox DataGrid
, etc. so that the user cannot change the value but easily view the data. Developer’s immediate thought will go for disabling the control simply. This is because; if we set “IsEnabled
” property to false
to parent control/element, then all the child controls/elements will also be disabled. But, it is not preferred to go for disabling the controls for the reasons not limited to but includes:
- User will not able to copy the text from the
TextBox
- Scrollbar will not work hence data will not be viewed fully
- Expander cannot be expanded or collapsed
- Overall look and feel is not good from end user perspective
However, we don’t have similar kind of approach available to set read only state hierarchically since not all controls have the “IsReadOnly
” property.
Background
Fair knowledge about the following topics is required to understand this article better:
- Resources & Resource Dictionaries
- Styles & Triggers
- Attached properties
Using the Code
- Create a class similar to
ReadOnlyStyleHelper
- Create an attached property namely
AllowEdit
Refer to the below example:
public class ReadOnlyStyleHelper
{
public static readonly DependencyProperty AllowEditProperty =
DependencyProperty.RegisterAttached("AllowEdit", typeof(bool),
typeof(ReadOnlyStyleHelper), new FrameworkPropertyMetadata(true,FrameworkPropertyMetadataOptions.Inherits));
public static bool GetAllowEdit(DependencyObject obj)
{
return (bool)obj.GetValue(AllowEditProperty);
}
public static void SetAllowEdit(DependencyObject obj, bool value)
{
obj.SetValue(AllowEditProperty, value);
}
}
Note the parameter “FrameworkPropertyMetadataOptions.Inherits
” which is responsible for property inheritance. It means that all child controls will inherit the property.
- Refer to the namespace of the attached property class (which is created in the previous step) in the target user control or window for which read-only style has to be applied.
- Set the attached property to top most element. You may use view model binding as well based on requirement.
Write style for controls like TextBox
, CheckBox
, DataGrid
, etc. as below:
<Style TargetType="{x:Type CheckBox}">
<Style.Triggers>
<Trigger Property="localUtils:ReadOnlyStyleHelper.AllowEdit" Value="False">
<Setter Property="IsHitTestVisible" Value="False"/>
<Setter Property="Focusable" Value="False"></Setter>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="localUtils:ReadOnlyStyleHelper.AllowEdit" Value="False">
<Setter Property="IsReadOnly" Value="True"/>
</Trigger>
</Style.Triggers>
</Style>
Note: Apply key attribute if you want to apply this style to specific controls rather than all instances.
Create a Resource Dictionary using the above styles.
Refer or merge the above created resource dictionary in the top most user control, window or even App.Xaml.
Points of Interest
The idea is to go for some attached property as we don’t have read-only property available for all controls. But, it is not necessary to set this property to each and every control, rather set it on the top most control or user-control or even window. Property inheritance can be achieved by WPF’s dependency property mechanism. We should apply read-only style for controls which are interested. Resource dictionary should be created by making use of the styles which need to be referred wherever required.
History
- 24th September, 2015: Initial version