방법: ICommandSource 구현
업데이트: 2007년 11월
이 예제에서는 ICommandSource를 구현하여 명령 소스를 만드는 방법을 보여 줍니다. 명령 소스는 명령 호출 방법을 아는 개체입니다. ICommandSource 인터페이스는 Command, CommandParameter 및 CommandTarget의 세 멤버를 노출합니다. Command는 호출될 명령입니다. CommandParameter는 명령 소스에서 명령을 처리하는 메서드로 전달되는 사용자 정의 데이터 형식입니다. CommandTarget은 명령이 실행되는 개체입니다.
이 예제에서는 Slider 컨트롤을 서브클래싱하고 ICommandSource를 구현하는 클래스를 만듭니다. 전체 소스 코드를 보려면 ICommandSource 구현 샘플을 참조하십시오.
예제
WPF에서는 Button, MenuItem 및 ListBoxItem과 같은 ICommandSource를 구현하는 많은 클래스를 제공합니다. 명령 소스는 명령을 호출하는 방법을 정의합니다. Button 및 MenuItem의 경우 클릭했을 때 명령을 호출합니다. ListBoxItem은 두 번 클릭했을 때 명령을 호출합니다. 이러한 클래스는 Command 속성이 설정된 경우에만 명령 소스가 됩니다.
이 예제의 경우 슬라이더를 이동할 때, 더 정확하게는 Value 속성이 변경될 때 명령을 호출합니다.
다음은 클래스 정의입니다.
public class CommandSlider : Slider, ICommandSource
{
public CommandSlider() : base()
{
}
다음 단계에서는 ICommandSource 멤버를 구현합니다. 이 예제에서는 속성이 DependencyProperty 개체로 구현됩니다. 이를 통해 속성이 데이터 바인딩을 사용할 수 있습니다. DependencyProperty 클래스에 대한 자세한 내용은 종속성 속성 개요를 참조하십시오. 데이터 바인딩에 대한 자세한 내용은 데이터 바인딩 개요를 참조하십시오.
여기에는 Command 속성만 표시됩니다.
// 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 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 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 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 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);
}
}
}
ICommandSource 구현 샘플에서는 이 명령 소스를 사용하는 샘플 응용 프로그램을 만듭니다.