Creating overridable methods

The first thing that we need to do is to define either an abstract or a virtual method in our base class. Note that the class would need to be abstract in order to declare an abstract method. Which one we chose will depend on if we want to leave the implementation up to the developers that use our code, or if we have some implementation that we need to put in the method ourselves.

Let's look at an example to clarify this. Here, we see a method from an abstract BaseDragDropManager class. It handles the PreviewMouseMove event on controls that are used as drag and drop sources, for example, on a ListBox from which an item is being dragged:

private void DragSourcePreviewMouseMove(object sender, MouseEventArgs e) 
{ 
  if (_isMouseDown && IsConfirmedDrag(e.GetPosition(sender as ListBox))) 
  { 
    _isMouseDown = false; 
    OnDragSourcePreviewMouseMove(sender, e); 
    if (e.Handled) return; 
    OnDragStart(sender as UIElement); 
  } 
} 

protected virtual void
OnDragSourcePreviewMouseMove(object sender, MouseEventArgs e) { }
protected abstract void OnDragStart(UIElement uiElement);

In this example, the DragSourcePreviewMouseMove method first performs a check to verify that a drag operation has been initiated by the user. It then calls the OnDragSourcePreviewMouseMove method, which is marked as virtual, which makes overriding it in derived classes optional.

The next line of the DragSourcePreviewMouseMove method checks the Handled property of the MouseEventArgs input parameter and if it has been set to true in the derived class, it returns execution to the caller, instead of continuing with the drag and drop operation. If the event has not been handled, then the OnDragStart method is called.

This is the crucial bit that links the possible input from the derived classes. The only reason to override the OnDragSourcePreviewMouseMove method in an extending class is to set the Handled property of the MouseEventArgs input parameter to true and stop the drag and drop operation from starting, perhaps according to some information that the extending class has.

Conversely, the OnDragStart method is marked as abstract, requiring it to be overridden in all derived classes. This is the method that prepares the data for the drag and drop process, and is required to call the StartDrag method of the base class to start the operation, passing the prepared data.

In this particular example, our virtual method is left empty in the base class and there is no need to call it from the overridden method. More typically, the base class would contain a default implementation, which could be overridden in derived classes, but may require a call to the base class, in order to retain its functionality.

For example, a .NET Framework programming guideline exists for raising base class events from derived classes. Ordinarily, derived classes cannot raise base class events and any attempts to do so will be met with a compilation error:

The event ClassName.EventName can only appear on the left hand side of += or -= (except when used from within the type ClassName)

The solution to this problem from the guidelines is to wrap the invocation of these events in a protected method in the base class, so it can be called or overridden in derived classes. Let's add a custom EventArgs class and an event into our AddressControl control that demonstrates this guideline:

public class AddressEventArgs : EventArgs 
{ 
  public AddressEventArgs(Address oldAddress, Address newAddress) 
  { 
    OldAddress = oldAddress; 
    NewAddress = newAddress; 
  } 
 
  public Address OldAddress { get; } 
 
  public Address NewAddress { get; } 
} 
 
... 
 
public event EventHandler<AddressEventArgs> AddressChanged;  
 
... 
 
public virtual Address Address 
{ 
  get { return (Address)GetValue(AddressProperty); } 
  set 
  { 
    if (!Address.Equals(value)) 
    { 
      Address oldAddress = Address; 
      SetValue(AddressProperty, value); 
      OnAddressChanged(new AddressEventArgs(oldAddress, value)); 
    } 
  } 
} 
 
... 
 
protected virtual void OnAddressChanged(AddressEventArgs e) 
{ 
  AddressChanged?.Invoke(this, e); 
} 

First, we create a custom EventArgs class for our event. Then, we declare an event named AddressChanged and a protected virtual method that raises it, using the null conditional operator. This can be called directly from derived classes to raise the event, but also overridden, to add to or to stop the base class implementation from executing.

Finally, we update our Address property to call the invocation method, passing in the required previous and current Address objects. Note that we now also mark this property as virtual, so that derived classes can override it as well, to fully control how, when and if the event should be raised.

This is a far more preferable solution to declaring a virtual event and overriding it in a derived class, as the compiler does not always handle this situation as expected, due to some complicated event overriding rules, and we cannot always be certain which version of the event a subscriber will actually by subscribing to.

Now that we have a better understanding of these protected methods, let's take a look at what other kinds of things we can do by overriding them in derived classes. We will use an extended example that raises a number of problems, that we can fix by overriding a number of these protected base class methods.