Derived Controls


If an existing control does almost what you need to do, you can derive a new control from the existing one. That enables you to take advantage of all of the existing control’s features while adding new ones of your own.

To make a derived control, start a control library project as usual and give the library a meaningful name. Discard the default UserControl1 class, add a new class, and give it an appropriate Inherits statement. For example, the following code derives the RowSortingListView class from the ListView class:

  Public Class RowSortingListView     Inherits ListView End Class 

That’s about all there is to building a derived control. Now you just need to write code that implements the new features and modifies inherited features. One particularly common task for derived controls is overriding the functionality provided by the parent control class. The RowSortingListView control provides a good example.

The standard ListView control lets a program display data items with subitems in a variety of ways. The control can display items as large icons, small icons, a list showing the items’ names, or a detail list showing the items and their subitems. The list and detail displays even allow you to sort the items in ascending and descending order. Unfortunately, the ListView control doesn’t use the subitems in the sort even to break ties. It sorts only on the main items’ names.

For example, suppose that several items all have the item value Book and their first subitems contain book titles. If you set the ListView control’s Sorting property to Ascending or Descending, the control will group these items together because they all have the same item value: Book. Unfortunately, the items’ order in the list is arbitrary. The control does not sort the Book items by their titles.

Fortunately, the ListView control provides a back door for implementing custom sort orders. To implement a custom sort order, you set the ListView control’s ListViewItemSorter property to an object that implements the IComparer interface. To satisfy the interface, this object must provide a Compare function that compares two ListView items and returns -1, 0, or 1 if the first item should be considered less than, equal to, or greater than the second item.

The ListViewComparerAllColumns class shown in the following code implements the IComparer interface. Its private m_SortOrder variable tells the object whether to sort in ascending or descending order. The class’s constructor takes a parameter that sets this value. The Compare function converts the generic Objects that it is passed into ListViewItems. It calls the ListViewItemValue helper function to get strings containing the items and their subitems separated by Tab characters. It then uses the String class’s Compare method to determine which value should come first in the sort order.

  ' Implements a ListViewItem comparer  ' that sorts on all columns. Private Class ListViewComparerAllColumns     Implements IComparer     ' Ascending or Descending.     Private m_SortOrder As SortOrder     ' Initialize with a sort order.     Public Sub New(ByVal sort_order As SortOrder)         m_SortOrder = sort_order     End Sub     ' Compare two items' subitems.     Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer _      Implements System.Collections.IComparer.Compare         ' Get the ListViewItems.         Dim item_x As ListViewItem = DirectCast(x, ListViewItem)         Dim item_y As ListViewItem = DirectCast(y, ListViewItem)         ' Get the ListViewItems' values.         Dim values_x As String = ListViewItemValue(item_x)         Dim values_y As String = ListViewItemValue(item_y)         ' Compare the values.         If m_SortOrder = SortOrder.Ascending Then             Return String.Compare(values_x, values_y)         Else             Return String.Compare(values_y, values_x)         End If     End Function     ' Return a delimited string containing all of     ' the ListViewItem's values.     Private Function ListViewItemValue(ByVal lvi As ListViewItem, _      Optional ByVal delimiter As String = vbTab) As String         Dim txt As String = ""         For i As Integer = 0 To lvi.SubItems.Count - 1             txt &= delimiter & lvi.SubItems(i).Text         Next i         Return txt.Substring(delimiter.Length)     End Function End Class  

The RowSortingListView control uses the ListViewComparerAllColumns class and the following code to sort its data using all of the items’ values and their subitems’ values. To provide the new sorting behavior, the control must override the Sorting property defined by the parent ListView class.

The control defines a private m_Sorting variable to store the property’s value and declares property procedures to let the program get and set it. The property is declared with the Shadows keyword, so it hides the definition of the parent class’s Sorting property. That prevents the developer or a program that uses the RowSortingListView control from using the original ListView version of the property.

The Sorting Property Get procedure simply returns the value of m_Sorting.

The Property Set procedure saves the new value. Then if the new Sorting value is None, the code sets the control’s inherited ListViewItemSorter property to Nothing to remove any previously installed sorter object. If Sorting is not None, the code sets the control’s ListViewItemSorter property to a new ListViewComparerAllColumns object configured to sort the items in the proper order.

  ' Reimplement the Sorting property. Private m_Sorting As SortOrder Public Shadows Property Sorting() As SortOrder     Get         Return m_Sorting     End Get     Set(ByVal Value As SortOrder)         ' Save the new value.         m_Sorting = Value         ' Make a new ListViewItemSorter if necessary.         If m_Sorting = SortOrder.None Then             MyBase.ListViewItemSorter = Nothing         Else             MyBase.ListViewItemSorter = _                 New ListViewComparerAllColumns(m_Sorting)         End If     End Set End Property  

Adding new properties and methods that don’t shadow those of the base class is even easier. Simply declare the property or method as you would for any other class. You can also create new events for the derived control just as you would add events to any other class.

Shadowing Parent Features

The RowSortingListView control’s code implements a Sorting property that shadows the property in its parent class. You can provide new versions of methods and events in the same way.

For example, normally, the ListView control raises a ColumnClick event when the user clicks on a column header. By default, the RowSortingListView control inherits that behavior, so it also raises the event when the user clicks on a column header.

The following code replaces the parent class’s ColumnClick event with a new version. The event declaration uses the Shadows keyword so this version hides the parent’s version from the program that uses the RowSortingListView control so the program cannot receive the original version of the event. The inherited version of ColumnClick passes the event handler a parameter that gives information about the event. The new version just returns the index of the column clicked. The control’s ColumnClick event handler (which handles the MyBase.ColumnClick event) raises the new event handler. The control could also raise the event from some other code or not at all.

  Public Shadows Event ColumnClick(ByVal column_number As Integer) Private Sub RowSortingListView_ColumnClick(ByVal sender As Object, _  ByVal e As System.Windows.Forms.ColumnClickEventArgs) Handles MyBase.ColumnClick     RaiseEvent ColumnClick(e.Column) End Sub 

The following code shows how a program could handle the new event. This code simply displays the column number that the user clicked.

  Private Sub RowSortingListView1_ColumnClick(ByVal column_number As Integer) _  Handles RowSortingListView1.ColumnClick     MessageBox.Show(column_number) End Sub 

In the same way, you can shadow a method provided by the parent class. The following code shows how the RowSortingListView class can replace its parent’s Clear method. Instead of removing all of the data from the control, this version removes only items with text value Book.

  Public Shadows Sub Clear()     For Each item As ListViewItem In Me.Items         If item.Text = "Book" Then item.Remove()     Next item End Sub 

Hiding Parent Features

Sometimes you might want to completely hide a parent feature rather than replace it with a new version. Hiding an event is easy. Declare a new event with the Shadows keyword as described in the previous section and then never raise the event. A program using the control can write an event handler for the event, but it will never be called.

Hiding properties and methods is a little more difficult. One approach you might try would be to create a private version of the property or method with the Shadows keyword. For example, the intent of the following code is to hide the control’s inherited Clear method. The idea is that the Private keyword makes the method inaccessible to the program and the Shadows keyword hides the parent’s version.

  Private Shadows Sub Clear()     For Each item As ListViewItem In Me.Items         If item.Text = "A" Then item.Remove()     Next item End Sub 

Unfortunately, if you use the Shadows keyword but the program cannot see the property or method (in this case, because it is private), Visual Basic exposes the parent’s version. This approach won’t work.

Although you can’t completely hide inherited properties and methods from the program using the control, you can disable them. The following code declares a shadowing version of the ListView control’s Clear method. If the program invokes this method, the control throws the MissingMethodException. If the program catches the error, the exception object’s error message says, “Method RowSortingListView.Clear not found.” Next the code defines a shadowing version of the Tag property. It gives the property the BrowsableAttribute with the value False. This prevents the property from appearing in the Properties window at design time. If the program tries to read or set the control’s Tag property at runtime, the control throws a MissingFieldException. If the program catches the error, the exception object’s error message says, “Field RowSortingListView.Tag not found.”

  Public Shadows Sub Clear()     Throw New System.MissingMethodException("RowSortingListView", "Clear") End Sub <System.ComponentModel.BrowsableAttribute(False)> _ Public Shadows Property Tag() As Object     Get         Throw New System.MissingFieldException("RowSortingListView", "Tag")     End Get     Set(ByVal Value As Object)         Throw New System.MissingFieldException("RowSortingListView", "Tag")     End Set End Property  




Visual Basic 2005 with  .NET 3.0 Programmer's Reference
Visual Basic 2005 with .NET 3.0 Programmer's Reference
ISBN: 470137053
EAN: N/A
Year: 2007
Pages: 417

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net