windowsforms-7071-controls-and-libraries-rich-text-editor-examples-commands-how-to-bind-a-command-to-a-button.md
A command can be bound to virtually any UI element. This example demonstrates a simple case - how to bind the UndoCommand command to a SimpleButton control.
First, we create a descendant of the SimpleButton class, named CommandButton. Then, add two fields which will distinguish it from a simple button - one field to hold a Command object, the other - to hold a RichEditControl. Add corresponding properties with getters and setters.
The Initialize method will perform an initial assignment of the control and command identifier, both of which are required to create a command for the command button. The command itself is obtained in the CreateCommand method.
Note
You should always create a new instance of a command before execution.
Subscribe to the RichEditControl.UpdateUI event of the RichEditControl to be notified about changes affecting the control’s user interface. The handler for this event should be able to update the UI for the command. We name this method “ OnUpdateUI “. Notice that setters for the Command and RichEditControl properties should also call the OnUpdateUI method.
To update the command UI we need an object representing the command UI state of our CommandButton. Let’s name it CommandButtonUIState. It inherits from the ICommandUIState interface and implements the ICommandUIState.Checked, the ICommandUIState.Enabled and theICommandUIState.Visible properties. The OnUpdateUI method creates a command instance, the CommandButtonUIState instance and updates the command UI state by calling the command’s Command.UpdateUIState method.
The setter for the Command property calls the OnUpdateUI method. The setter for the RichEditControl property unsubscribes from the RichEditControl.UpdateUI event before assignment, then subscribes back to UpdateUI event and calls the OnUpdateUI method.
The final step is to override the OnClick method in our SimpleButton descendant. When a CommandButton is clicked, it will create a command object instance and execute a command by calling its Command.Execute method.
The following code demonstrates the implementation of the technique described above:
public class CommandButton : SimpleButton {
RichEditCommandId commandId;
RichEditControl control;
public void Initialize(RichEditControl initControl,RichEditCommandId initId)
{
UnsubscribeControlEvents();
control = initControl;
commandId = initId;
SubscribeControlEvents();
}
public RichEditControl RichEditControl {
get { return control; }
set {
if(control == value)
return;
UnsubscribeControlEvents();
this.control = value;
SubscribeControlEvents();
OnUpdateUI(this, EventArgs.Empty);
}
}
public RichEditCommandId CommandId
{
get { return commandId; }
set {
if (commandId == value)
return;
commandId = value;
OnUpdateUI(this, EventArgs.Empty);
}
}
void SubscribeControlEvents() {
if(control == null)
return;
control.UpdateUI += OnUpdateUI;
}
void UnsubscribeControlEvents() {
if(control == null)
return;
control.UpdateUI -= OnUpdateUI;
}
void OnUpdateUI(object sender, EventArgs e) {
Command command = CreateCommand();
if(command != null) {
CommandButtonUIState state = new CommandButtonUIState(this);
command.UpdateUIState(state);
}
}
protected override void OnClick(EventArgs e) {
base.OnClick(e);
Command command = CreateCommand();
if(command != null)
command.Execute();
}
// You may override this method to create a command
protected virtual Command CreateCommand() {
return control.CreateCommand(commandId);
}
}
Public Class CommandButton
Inherits SimpleButton
Private commandId_Renamed As RichEditCommandId
Private control As RichEditControl
Public Sub Initialize(ByVal initControl As RichEditControl, ByVal initId As RichEditCommandId)
UnsubscribeControlEvents()
control = initControl
commandId_Renamed = initId
SubscribeControlEvents()
End Sub
Public Property RichEditControl() As RichEditControl
Get
Return control
End Get
Set(ByVal value As RichEditControl)
If control Is value Then
Return
End If
UnsubscribeControlEvents()
Me.control = value
SubscribeControlEvents()
OnUpdateUI(Me, EventArgs.Empty)
End Set
End Property
Public Property CommandId() As RichEditCommandId
Get
Return commandId_Renamed
End Get
Set(ByVal value As RichEditCommandId)
If commandId_Renamed = value Then
Return
End If
commandId_Renamed = value
OnUpdateUI(Me, EventArgs.Empty)
End Set
End Property
Private Sub SubscribeControlEvents()
If control Is Nothing Then
Return
End If
AddHandler control.UpdateUI, AddressOf OnUpdateUI
End Sub
Private Sub UnsubscribeControlEvents()
If control Is Nothing Then
Return
End If
RemoveHandler control.UpdateUI, AddressOf OnUpdateUI
End Sub
Private Sub OnUpdateUI(ByVal sender As Object, ByVal e As EventArgs)
Dim command As Command = CreateCommand()
If command IsNot Nothing Then
Dim state As New CommandButtonUIState(Me)
command.UpdateUIState(state)
End If
End Sub
Protected Overrides Sub OnClick(ByVal e As EventArgs)
MyBase.OnClick(e)
Dim command As Command = CreateCommand()
If command IsNot Nothing Then
command.Execute()
End If
End Sub
' You may override this method to create a command
Protected Overridable Function CreateCommand() As Command
Return control.CreateCommand(commandId_Renamed)
End Function
End Class
public class CommandButtonUIState : ICommandUIState {
readonly SimpleButton button;
public CommandButtonUIState(SimpleButton button) {
this.button = button;
}
#region ICommandUIState Members
public bool Checked { get { return false; } set {} }
public bool Enabled { get { return button.Enabled; } set { button.Enabled = value; } }
public bool Visible { get { return button.Visible; } set { button.Visible = value; } }
public virtual object EditValue { get { return null; } set { } }
}
Public Class CommandButtonUIState
Implements ICommandUIState
Private ReadOnly button As SimpleButton
Public Sub New(ByVal button As SimpleButton)
Me.button = button
End Sub
#Region "ICommandUIState Members"
Public Property Checked() As Boolean Implements ICommandUIState.Checked
Get
Return False
End Get
Set(ByVal value As Boolean)
End Set
End Property
Public Property Enabled() As Boolean Implements ICommandUIState.Enabled
Get
Return button.Enabled
End Get
Set(ByVal value As Boolean)
button.Enabled = value
End Set
End Property
Public Property Visible() As Boolean Implements ICommandUIState.Visible
Get
Return button.Visible
End Get
Set(ByVal value As Boolean)
button.Visible = value
End Set
End Property
Public Overridable Property EditValue() As Object Implements ICommandUIState.EditValue
Get
Return Nothing
End Get
Set(ByVal value As Object)
End Set
End Property
btnUndo.Initialize(richEditControl1, RichEditCommandId.Undo);
btnUndo.Initialize(richEditControl1, RichEditCommandId.Undo)
The Command Button technique seems rather straightforward, although it has its own drawbacks. It forces us to create as many descendant classes as there are user interface elements for which command binding is required. The next step is implementing a Command Adapter object which can serve as a helpful generalization of a command UI binding solution. A command adapter contains an additional field representing a UI element, the SimpleButton in our case. The CommandButtonAdapter implementation is demonstrated in the CodeCentral example.