Practical .NET
Integrating with the .NET Framework UI Controls
With a little bit of code (along with a .NET interface and collection), you can integrate the properties on your classes with the .NET user interface controls to simplify your presentation layer.
The .NET Framework team obviously assumes you'll build your applications and the classes that make up your application a certain way. If you leverage those assumptions you'll get lots of cool benefits (and, if you don't leverage those benefits…well, you'll get to do a lot more work).
For instance, the user interface controls you can drag onto your WPF or Silverlight forms (TextBoxes, DropDownList, and so on) assume that you'll bind class properties to them. Those controls look for specific features in your classes; if you build those features into your code, you'll get a lot of functionality for free. The benefit is that you can build those objects independent of your UI, which supports automated testing, parallel development and loose coupling between application components.
One example of how you can integrate your classes with a XAML UI is the INotifyPropertyChanged interface. Adding this interface (and some code) to your classes gives you some almost magical benefits. For instance, if you have an object whose property is bound to and displayed in some user interface control, the control will automatically update in your user interface if you update the property from code. There's no need to do anything to make the user interface display the property's latest value: you don't need to update the control or call a Refresh method on the control (or the form).
Adding the INotifyPropertyChanged interface to your class is easy:
Public Class Product
Implements ComponentModel.INotifyPropertyChanged
Visual Studio will then add the interface's one required member, an event called PropertyChanged:
Public Event PropertyChanged(sender As Object,
e As System.ComponentModel.PropertyChangedEventArgs) Implements _
System.ComponentModel.INotifyPropertyChanged.PropertyChanged
The .NET UI controls look for this interface, and when they find it, automatically subscribe to any PropertyChanged methods you fire. In those events, you need only pass the name of the property being changed to cause the .NET user interface controls to pick up and display the latest value for the property. The typical place to put that is in the setter of the property being changed:
Private _Description As String
Public Property Description As String
Get
Return _Description
End Get
Set(value As String)
_Description = value
RaiseEvent PropertyChanged(Me,
New ComponentModel.PropertyChangedEventArgs("Description"))
End Set
End Property
Rather than repeat the RaiseEvent code in every property, it makes sense to centralize it in a method of your own, like this:
Private Sub RaisePropertyChanged(PropertyName As String)
RaiseEvent PropertyChanged(Me,
New ComponentModel.PropertyChangedEventArgs(PropertyName))
End Sub
With properties that are dependent on other properties, you may want to raise an event in other locations than the setter of a property. For instance, let's say you have a readonly ExtendedPrice property that's calculated from two other properties, Price and Quantity:
Public ReadOnly Property ExtendedPrice As Decimal
Get
Return Me.Price * Me.Quantity
End Get
End Property
In that case, changing either the Price or Quantity properties not only changes the property being updated, but also changes the ExtendedPrice property. To support that you'd want to raise the property changed event for all the affected properties in the setter of the properties that drive ExtendedPrice. The Quantity property would look like this:
Private _Quantity As Integer
Public Property Quantity As Integer
Get
Return _Quantity
End Get
Set(value As Integer)
_Quantity = value
RaisePropertyChanged("Quantity")
RaisePropertyChanged("ExtendedPrice")
End Set
End Property
Now, when you update the Quantity property (or any property that calls your RaisePropertyChanged method), any UI control tied to your Quantity or ExtendedPrice will automatically display the change. The only entanglement between your classes and the UI is when you set the data source on the UI control to an instance of your class.
However, sometimes you bind your controls to collections of objects—DataGridViews, for instance. In those scenarios, it's not enough to notify the UI control of changes in properties—you also want to notify the control about additions or deletions in the list of objects to which the control is bound. Here again, the .NET Framework provides a solution: The ObservableCollection generic collection class. As you create the objects that will be displayed, just pass the collection to the grid's ItemSource property:
Dim prods As New ObjectModel.ObservableCollection(Of Product)
prods.Add(New Product("A123"))
prods.Add(New Product("B456"))
Me.DataGrid1.ItemsSource = prods
Now, if in your code you add or remove an item from the custs collection, your UI will update automatically. You could write code to make that happen yourself; but by leveraging the INotifyPropertyChanged interface and the ObservableCollection class, you get all of the benefits, and minimize the entanglements between your UI and your classes.
About the Author
Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.