방법: ICommandSource 구현
이 예제에서는 ICommandSource를 구현하여 명령 소스를 만드는 방법을 보여 줍니다. 명령 소스는 명령 호출 방법을 아는 개체입니다. ICommandSource 인터페이스는 Command, CommandParameter 및 CommandTarget의 세 멤버를 노출합니다. Command는 호출될 명령입니다. CommandParameter는 명령 소스에서 명령을 처리하는 메서드로 전달되는 사용자 정의 데이터 형식입니다. CommandTarget은 명령이 실행되는 개체입니다.
이 예제에서는 Slider 컨트롤을 서브클래싱하고 ICommandSource를 구현하는 클래스를 만듭니다.
예제
WPF에서는 Button, MenuItem 및 ListBoxItem과 같은 ICommandSource를 구현하는 많은 클래스를 제공합니다. 명령 소스는 명령을 호출하는 방법을 정의합니다. Button 및 MenuItem의 경우 클릭했을 때 명령을 호출합니다. ListBoxItem은 두 번 클릭했을 때 명령을 호출합니다. 이러한 클래스는 Command 속성이 설정된 경우에만 명령 소스가 됩니다.
이 예제의 경우 슬라이더를 이동할 때, 더 정확하게는 Value 속성이 변경될 때 명령을 호출합니다.
다음은 클래스 정의입니다.
Public Class CommandSlider
Inherits Slider
Implements ICommandSource
Public Sub New()
MyBase.New()
End Sub
public class CommandSlider : Slider, ICommandSource
{
public CommandSlider() : base()
{
}
다음 단계에서는 ICommandSource 멤버를 구현합니다. 이 예제에서는 속성이 DependencyProperty 개체로 구현됩니다. 이를 통해 속성이 데이터 바인딩을 사용할 수 있습니다. DependencyProperty 클래스에 대한 자세한 내용은 종속성 속성 개요를 참조하십시오. 데이터 바인딩에 대한 자세한 내용은 데이터 바인딩 개요를 참조하십시오.
여기에는 Command 속성만 표시됩니다.
' Make Command a dependency property so it can use databinding.
Public Shared ReadOnly CommandProperty As DependencyProperty =
DependencyProperty.Register("Command", GetType(ICommand),
GetType(CommandSlider),
New PropertyMetadata(CType(Nothing, ICommand),
New PropertyChangedCallback(AddressOf CommandChanged)))
Public ReadOnly Property Command1() As ICommand Implements ICommandSource.Command
Get
Return CType(GetValue(CommandProperty), ICommand)
End Get
End Property
Public Property Command() As ICommand
Get
Return CType(GetValue(CommandProperty), ICommand)
End Get
Set(ByVal value As ICommand)
SetValue(CommandProperty, value)
End Set
End Property
// Make Command a dependency property so it can use databinding.
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register(
"Command",
typeof(ICommand),
typeof(CommandSlider),
new PropertyMetadata((ICommand)null,
new PropertyChangedCallback(CommandChanged)));
public ICommand Command
{
get
{
return (ICommand)GetValue(CommandProperty);
}
set
{
SetValue(CommandProperty, value);
}
}
다음은 DependencyProperty 변경 콜백입니다.
' Command dependency property change callback.
Private Shared Sub CommandChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
Dim cs As CommandSlider = CType(d, CommandSlider)
cs.HookUpCommand(CType(e.OldValue, ICommand), CType(e.NewValue, ICommand))
End Sub
// Command dependency property change callback.
private static void CommandChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
CommandSlider cs = (CommandSlider)d;
cs.HookUpCommand((ICommand)e.OldValue,(ICommand)e.NewValue);
}
다음 단계에서는 명령 소스와 연결된 명령을 추가 및 제거합니다. 이벤트 처리기가 이전 명령과 연결되어 있으므로 새 명령이 추가될 때 Command 속성을 단순하게 덮어쓸 수는 없으며 이러한 속성이 있는 경우 먼저 제거해야 합니다.
' Add a new command to the Command Property.
Private Sub HookUpCommand(ByVal oldCommand As ICommand, ByVal newCommand As ICommand)
' If oldCommand is not null, then we need to remove the handlers.
If oldCommand IsNot Nothing Then
RemoveCommand(oldCommand, newCommand)
End If
AddCommand(oldCommand, newCommand)
End Sub
' Remove an old command from the Command Property.
Private Sub RemoveCommand(ByVal oldCommand As ICommand, ByVal newCommand As ICommand)
Dim handler As EventHandler = AddressOf CanExecuteChanged
RemoveHandler oldCommand.CanExecuteChanged, handler
End Sub
' Add the command.
Private Sub AddCommand(ByVal oldCommand As ICommand, ByVal newCommand As ICommand)
Dim handler As New EventHandler(AddressOf CanExecuteChanged)
canExecuteChangedHandler = handler
If newCommand IsNot Nothing Then
AddHandler newCommand.CanExecuteChanged, canExecuteChangedHandler
End If
End Sub
// Add a new command to the Command Property.
private void HookUpCommand(ICommand oldCommand, ICommand newCommand)
{
// If oldCommand is not null, then we need to remove the handlers.
if (oldCommand != null)
{
RemoveCommand(oldCommand, newCommand);
}
AddCommand(oldCommand, newCommand);
}
// Remove an old command from the Command Property.
private void RemoveCommand(ICommand oldCommand, ICommand newCommand)
{
EventHandler handler = CanExecuteChanged;
oldCommand.CanExecuteChanged -= handler;
}
// Add the command.
private void AddCommand(ICommand oldCommand, ICommand newCommand)
{
EventHandler handler = new EventHandler(CanExecuteChanged);
canExecuteChangedHandler = handler;
if (newCommand != null)
{
newCommand.CanExecuteChanged += canExecuteChangedHandler;
}
}
마지막 단계에서는 CanExecuteChanged 처리기와 Execute 메서드에 대한 논리를 만듭니다.
CanExecuteChanged 이벤트는 현재 명령 대상에 대해 실행할 수 있는 명령의 기능이 변경되었을 수 있음을 명령 소스에 알립니다. 명령 소스가 이 이벤트를 수신하면 일반적으로 명령에 대해 CanExecute 메서드를 호출합니다. 명령을 현재 명령 대상에 대해 실행할 수 없는 경우 명령 소스는 대개 자체적으로 비활성화됩니다. 명령을 현재 명령 대상에 대해 실행할 수 있는 경우 명령 소스는 대개 자체적으로 활성화됩니다.
Private Sub CanExecuteChanged(ByVal sender As Object, ByVal e As EventArgs)
If Me.Command IsNot Nothing Then
Dim command As RoutedCommand = TryCast(Me.Command, RoutedCommand)
' If a RoutedCommand.
If command IsNot Nothing Then
If command.CanExecute(CommandParameter, CommandTarget) Then
Me.IsEnabled = True
Else
Me.IsEnabled = False
End If
' If a not RoutedCommand.
Else
If Me.Command.CanExecute(CommandParameter) Then
Me.IsEnabled = True
Else
Me.IsEnabled = False
End If
End If
End If
End Sub
private void CanExecuteChanged(object sender, EventArgs e)
{
if (this.Command != null)
{
RoutedCommand command = this.Command as RoutedCommand;
// If a RoutedCommand.
if (command != null)
{
if (command.CanExecute(CommandParameter, CommandTarget))
{
this.IsEnabled = true;
}
else
{
this.IsEnabled = false;
}
}
// If a not RoutedCommand.
else
{
if (Command.CanExecute(CommandParameter))
{
this.IsEnabled = true;
}
else
{
this.IsEnabled = false;
}
}
}
}
마지막 단계는 Execute 메서드입니다. 명령이 RoutedCommand인 경우 RoutedCommand Execute 메서드가 호출되고, 그렇지 않은 경우에는 ICommand Execute 메서드가 호출됩니다.
' If Command is defined, moving the slider will invoke the command;
' Otherwise, the slider will behave normally.
Protected Overrides Sub OnValueChanged(ByVal oldValue As Double, ByVal newValue As Double)
MyBase.OnValueChanged(oldValue, newValue)
If Me.Command IsNot Nothing Then
Dim command As RoutedCommand = TryCast(Me.Command, RoutedCommand)
If command IsNot Nothing Then
command.Execute(CommandParameter, CommandTarget)
Else
CType(Me.Command, ICommand).Execute(CommandParameter)
End If
End If
End Sub
// If Command is defined, moving the slider will invoke the command;
// Otherwise, the slider will behave normally.
protected override void OnValueChanged(double oldValue, double newValue)
{
base.OnValueChanged(oldValue, newValue);
if (this.Command != null)
{
RoutedCommand command = Command as RoutedCommand;
if (command != null)
{
command.Execute(CommandParameter, CommandTarget);
}
else
{
((ICommand)Command).Execute(CommandParameter);
}
}
}