Introduction
Windows Forms databinding has greatly improved in .NET 2.0. Microsoft has enhanced our object-oriented toolbox by allowing Windows Forms controls to databind to our custom objects' properties. This new functionality is centered around the new BindingSource
component. Although this component takes a lot of the leg-work out of databinding custom objects, I recently had an issue with some rather large objects that contained both Read-Write
and ReadOnly
properties. After setting up databinding, I had to go through and manually set the "Enabled
" property of these controls depending on whether each individual property was ReadOnly
or not. I decided to create a custom BindingSource
component that would take care of this manual process in the background.
Background
Another option that I considered exploring was creating a custom attribute to add to the properties that I wanted to have ReadOnly
or Read-Write
capabilities to. The reason I didn't do this was that I wanted to avoid requiring the business object developer having to implement more than what is necessary just to satisfy the UI developer.
Using the code
We start off by creating a class library that will contain our custom SmartPropertyBindingSource
component and our ReadOnlyBehavior
enumeration. This enumeration will be used to determine the rendering behavior of the databound control. This class library project should reference the System.Windows.Forms
and set it to be a globally imported namespace (you may also just write Imports System.Windows.Forms
at the top of the SmartPropertyBindingSource.vb file).
We will be supporting two options for how the databound control of the ReadOnly
property will be rendered on the form. This is set through the ReadOnlyControlBehavior
property in the SmartPropertyBindingSource
. You can choose to have it disabled or hidden.
Public Enum ReadOnlyBehavior
Disable = 0
Hide = 1
End Enum
We will now add a class named SmartPropertyBindingSource
which inherits from BindingSource
.
Public Class SmartPropertyBindingSource
Inherits BindingSource
End Class
Next, we will create a Public
property in this class to set the control rendering behavior for ReadOnly
properties.
Public Property ReadOnlyControlBehavior() As ReadOnlyBehavior
Get
Return mReadOnlyBehavior
End Get
Set(ByVal value As ReadOnlyBehavior)
mReadOnlyBehavior = value
End Set
End Property
We will also go ahead and provide overloads for the three constructors in the base class. Once we have done this, we are ready to write the functionality of the class. By overriding the OnBindingComplete
, we will have access to the current object's property information, thanks to the System.Reflection
namespace. With this information, we will be able to find out if the property in question is ReadOnly
.
Protected Overrides Sub OnBindingComplete(ByVal e As _
System.Windows.Forms.BindingCompleteEventArgs)
Dim t As Type = e.Binding.BindingManagerBase.Current.GetType
Dim prop As System.Reflection.PropertyInfo = _
t.GetProperty(e.Binding.BindingMemberInfo.BindingMember)
If Not prop.CanWrite Then
Select Case Me.ReadOnlyControlBehavior
Case ReadOnlyBehavior.Disable
e.Binding.Control.Enabled = False
Case ReadOnlyBehavior.Hide
e.Binding.Control.Visible = False
End Select
End If
MyBase.OnBindingComplete(e)
End Sub
That's all there is to it. Using reflection, we can investigate whether the property is ReadOnly
and render (or not render) the control appropriately. We also don't have to ask the domain object's developer to do anything special to improve the user experience.
Points of Interest
The new .NET 2.0 framework provides a great deal of enhanced functionality from the previous framework allowing for easier integration of custom business objects. We can build upon this functionality by customizing classes to better suit our needs.