StandardUICommand, XamlUICommand 및 ICommand를 사용하는 Windows 앱의 명령Commanding in Windows apps using StandardUICommand, XamlUICommand, and ICommand

이 항목에서는 Windows 애플리케이션의 명령에 대해 설명합니다.In this topic, we describe commanding in Windows applications. 특히, 사용하는 디바이스 및 입력 형식에 관계없이 XamlUICommandStandardUICommand 클래스를 ICommand 인터페이스와 함께 사용하여 다양한 컨트롤 형식에서 명령을 공유하고 관리하는 방법을 살펴보겠습니다.Specifically, we discuss how you can use the XamlUICommand and StandardUICommand classes (along with the ICommand interface) to share and manage commands across various control types, regardless of the device and input type being used.

공유 명령의 일반적인 용도를 나타내는 다이어그램: '즐겨찾기' 명령이 있는 다중 UI 화면

디바이스 및 입력 형식에 관계 없이 다양한 컨트롤 간에 명령 공유Share commands across various controls, regardless of device and input type

중요 APIImportant APIs

개요Overview

단추를 클릭하거나 상황에 맞는 메뉴에서 항목을 선택하는 등의 UI 상호 작용을 통해 명령을 직접 호출할 수 있습니다.Commands can be invoked directly through UI interactions like clicking a button or selecting an item from a context menu. 바로 가기 키, 제스처, 음성 인식, 자동화/접근성 도구 등의 입력 디바이스를 통해 간접적으로 호출할 수도 있습니다.They can also be invoked indirectly through an input device such as a keyboard accelerator, gesture, speech recognition, or an automation/accessibility tool. 호출한 후에는 컨트롤(편집 컨트롤의 텍스트 탐색), 창(뒤로 탐색) 또는 애플리케이션(종료)을 통해 명령을 처리할 수 있습니다.Once invoked, the command can then be handled by a control (text navigation in an edit control), a window (back navigation), or the application (exit).

명령은 텍스트를 삭제하거나 작업을 취소하는 등의 경우처럼 앱 내의 특정 상황에서 작동할 수도 있고, 오디오 음소거나 밝기 조정처럼 상황에 관계 없이 작동할 수도 있습니다.Commands can operate on a specific context within your app, such as deleting text or undoing an action, or they can be context-free, such as muting audio or adjusting brightness.

다음 이미지에서는 동일한 명령 중 일부를 공유하는 두 개의 명령 인터페이스(CommandBar 및 움직이는 상황별 CommandBarFlyout)를 보여 줍니다.The following image shows two command interfaces (a CommandBar and a floating contextual CommandBarFlyout) that share some of the same commands.

확장된 명령 모음Expanded Command bar
명령 모음Command bar

Microsoft 사진 갤러리의 상황에 맞는 메뉴Context menu in the Microsoft Photos gallery
Microsoft 사진 갤러리의 상황에 맞는 메뉴Context menu in the Microsoft Photos gallery

명령 상호 작용Command interactions

다양한 디바이스, 입력 형식 및 UI 화면이 명령 호출 방법에 영향을 미칠 수 있기 때문에 최대한 많은 명령 화면을 통해 명령을 노출하는 것이 좋습니다.Due to the variety of devices, input types, and UI surfaces that can affect how a command is invoked, we recommend exposing your commands through as many commanding surfaces as possible. 여기에는 살짝 밀기, MenuBar, CommandBar, CommandBarFlyout 및 전통적인 상황에 맞는 메뉴 조합이 포함될 수 있습니다.These can include a combination of Swipe, MenuBar, CommandBar, CommandBarFlyout, and traditional context menu.

중요한 명령에는 입력 관련 가속기를 사용합니다.For critical commands, use input-specific accelerators. 입력 가속기는 사용자가 사용하는 입력 디바이스에 따라 작업을 더 빠르게 수행할 수 있게 도와줍니다.Input accelerators let a user perform actions more quickly depending on the input device they're using.

다음은 다양한 입력 형식에 제공되는 일반적인 입력 가속기입니다.Here are some common input accelerators for various input types:

  • 포인터 - 마우스 및 펜 호버 단추Pointer - Mouse & Pen hover buttons
  • 키보드 - 바로 가기(액세스 키 및 가속기 키)Keyboard - Shortcuts (access keys and accelerator keys)
  • 터치 - 살짝 밀기Touch - Swipe
  • 터치 - 당겨서 데이터 새로 고침Touch - Pull to refresh data

애플리케이션의 기능을 보편적으로 사용할 수 있도록 입력 형식과 사용자 환경을 고려해야 합니다.You must consider the input type and user experiences to make your application's functionality universally accessible. 예를 들어 컬렉션(특히 사용자가 편집 가능한 컬렉션)에는 일반적으로 입력 디바이스에 따라 전혀 다른 방법으로 수행되는 다양한 명령이 포함됩니다.For example, collections (especially user editable ones) typically include a variety of specific commands that are performed quite differently depending on the input device.

다음 표는 몇 가지 일반적인 컬렉션 명령과 이러한 명령을 노출하는 방법을 보여줍니다.The following table shows some typical collection commands and ways to expose those commands.

명령Command 입력과 무관Input-agnostic 마우스 가속기Mouse accelerator 바로 가기 키Keyboard accelerator 터치 가속기Touch accelerator
항목 삭제Delete item 상황에 맞는 메뉴Context menu 호버 단추Hover button DEL 키DEL key 살짝 밀어 삭제Swipe to delete
항목에 플래그 지정Flag item 상황에 맞는 메뉴Context menu 호버 단추Hover button Ctrl+Shift+GCtrl+Shift+G 살짝 밀어 플래그 지정Swipe to flag
데이터 새로 고침Refresh data 상황에 맞는 메뉴Context menu 해당 없음N/A F5 키F5 key 당겨서 새로 고침Pull to refresh
즐겨찾기에 항목 추가Favorite an item 상황에 맞는 메뉴Context menu 호버 단추Hover button F, Ctrl+SF, Ctrl+S 살짝 밀어 즐겨찾기에 추가Swipe to favorite

상황에 맞는 메뉴를 항상 제공 관련된 모든 상황에 맞는 명령을 기존 상황에 맞는 메뉴 또는 CommandBarFlyout에 포함하는 것이 좋습니다. 둘 다 모든 입력 형식을 지원합니다.Always provide a context menu We recommend including all relevant contextual commands in a traditional context menu or CommandBarFlyout, as both are supported for all input types. 예를 들어 명령이 포인터 가리키기 이벤트 중에만 노출되는 경우에는 터치 전용 디바이스에 사용할 수 없습니다.For example, if a command is exposed only during a pointer hover event, it cannot be used on a touch-only device.

Windows 애플리케이션의 명령Commands in Windows applications

Windows 애플리케이션에서 명령 환경을 공유하고 관리할 수 있는 몇 가지 방법이 있습니다.There are a few ways you can share and manage commanding experiences in a Windows application. 클릭 같은 표준 상호 작용에 대한 이벤트 처리기를 코드 숨김에 정의하거나(이 방법은 UI의 복잡성에 따라 매우 비효율적일 수 있음), 표준 상호 작용에 대한 이벤트 수신기를 바인딩하거나, 컨트롤의 Command 속성을 명령 논리를 설명하는 ICommand 구현에 바인딩할 수 있습니다.You can define event handlers for standard interactions, such as Click, in code-behind (this can be quite inefficient, depending on the complexity of your UI), you can bind event listener for standard interactions to a shared handler, or you can bind the control's Command property to an ICommand implementation that describes the command logic.

코드 중복을 최소화하면서 효율적으로 명령 화면에 풍부하고 포괄적인 사용자 환경을 제공하려면 이 토픽에서 설명하는 명령 바인딩 기능을 사용하는 것이 좋습니다(표준 이벤트 처리는 개별 이벤트 토픽 참조).To provide rich and comprehensive user experiences across command surfaces efficiently and with minimal code duplication, we recommend using the command binding features described in this topic(for standard event handling, see the individual event topics).

컨트롤을 공유 명령 리소스에 바인딩하려면 ICommand 인터페이스를 직접 구현하거나, XamlUICommand 기본 클래스 또는 StandardUICommand 파생 클래스가 정의하는 플랫폼 명령 중 하나로 명령을 빌드하면 됩니다.To bind a control to a shared command resource, you can implement the ICommand interfaces yourself, or you can build your command from either the XamlUICommand base class or one of the platform commands defined by the StandardUICommand derived class.

  • ICommand 인터페이스(Windows.UI.Xaml.Input.ICommand 또는 System.Windows.Input.ICommand)를 사용하면 완전히 사용자 지정된 재사용 가능한 명령을 앱에 만들 수 있습니다.The ICommand interface (Windows.UI.Xaml.Input.ICommand or System.Windows.Input.ICommand) lets you create fully customized, reusable commands across your app.
  • XamlUICommand도 이 기능을 제공하지만, 명령 동작, 바로 가기 키(액세스 키 및 가속기 키), 아이콘, 레이블, 설명 등의 기본 제공 명령 속성을 노출하여 개발을 간소화합니다.XamlUICommand also provides this capability but simplifies development by exposing a set of built-in command properties such as the command behavior, keyboard shortcuts (access key and accelerator key), icon, label, and description.
  • StandardUICommand는 속성이 미리 정의되어 있는 표준 플랫폼 명령 세트에서 선택할 수 있으므로 더욱 간단합니다.StandardUICommand simplifies things further by letting you choose from a set of standard platform commands with predefined properties.

중요

UWP 애플리케이션에서는 선택하는 언어 프레임워크에 따라 명령이 Windows.UI.Xaml.Input.ICommand(C++) 또는 System.Windows.Input.ICommand(C#) 인터페이스로 구현됩니다.In UWP applications, commands are implementations of either the Windows.UI.Xaml.Input.ICommand (C++) or the System.Windows.Input.ICommand (C#) interface, depending on your chosen language framework.

StandardUICommand 클래스를 사용하는 명령 환경Command experiences using the StandardUICommand class

XamlUiCommand에서 파생되는(C++는 Windows.UI.Xaml.Input.ICommand에서 파생되고, C#은 System.Windows.Input.ICommand에서 파생) StandardUICommand 클래스는 아이콘, 키보드 바로 가기 키, 설명 같은 속성이 미리 정의되어 있는 표준 플랫폼 명령 세트를 노출합니다.Derived from XamlUiCommand (derived from Windows.UI.Xaml.Input.ICommand for C++ or System.Windows.Input.ICommand for C#), the StandardUICommand class exposes a set of standard platform commands with pre-defined properties such as icon, keyboard accelerator, and description.

StandardUICommandSave 또는 Delete처럼 일반적인 명령을 빠르고 일관적으로 정의할 수 있는 방법을 제공합니다.A StandardUICommand provides a quick and consistent way to define common commands such as Save or Delete. 개발자는 execute 및 canExecute 함수만 제공하면 됩니다.All you have to do is provide the execute and canExecute functions.

예제Example

StandardUICommand 샘플

StandardUICommandSampleStandardUICommandSample

이 예제의 코드 다운로드Download the code for this example
UWP 명령 샘플(StandardUICommand)UWP commanding sample (StandardUICommand)

이 예제에서는 StandardUICommand 클래스를 통해 구현된 항목 삭제 명령으로 기본 ListView를 개선하는 방법과 MenuBar, 살짝 밀기 컨트롤, 호버 단추 및 상황에 맞는 메뉴를 사용하여 다양한 입력 형식에 맞게 사용자 환경을 최적화하는 방법을 보여줍니다.In this example, we show how to enhance a basic ListView with a Delete item command implemented through the StandardUICommand class, while optimizing the user experience for a variety of input types using a MenuBar, Swipe control, hover buttons, and context menu.

참고

이 샘플에는 Microsoft Windows UI 라이브러리의 일부인 Microsoft.UI.Xaml.Controls NuGet 패키지가 필요합니다.This sample requires the Microsoft.UI.Xaml.Controls NuGet package, a part of the Microsoft Windows UI Library.

Xaml:Xaml:

샘플 UI에는 5개 항목의 ListView가 포함되어 있습니다.The sample UI includes a ListView of five items. Delete StandardUICommandMenuBarItem, SwipeItem, AppBarButton ContextFlyout 메뉴에 바인딩됩니다.The Delete StandardUICommand is bound to a MenuBarItem, a SwipeItem, an AppBarButton, and ContextFlyout menu.

<Page
    x:Class="StandardUICommandSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:StandardUICommandSample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:muxcontrols="using:Microsoft.UI.Xaml.Controls"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Page.Resources>
        <Style x:Key="HorizontalSwipe" 
               TargetType="ListViewItem" 
               BasedOn="{StaticResource ListViewItemRevealStyle}">
            <Setter Property="Height" Value="60"/>
            <Setter Property="Padding" Value="0"/>
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
            <Setter Property="VerticalContentAlignment" Value="Stretch"/>
            <Setter Property="BorderThickness" Value="0"/>
        </Style>
    </Page.Resources>

    <Grid Loaded="ControlExample_Loaded">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <StackPanel Grid.Row="0" 
                    Padding="10" 
                    BorderThickness="0,0,0,1" 
                    BorderBrush="LightBlue"
                    Background="AliceBlue">
            <TextBlock Style="{StaticResource HeaderTextBlockStyle}">
                StandardUICommand sample
            </TextBlock>
            <TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Margin="0,0,0,10">
                This sample shows how to use the StandardUICommand class to 
                share a platform command and consistent user experiences 
                across various controls.
            </TextBlock>
            <TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Margin="0,0,0,0">
                Specifically, we define a standard delete command and add it 
                to a variety of command surfaces, all of which share a common 
                icon, label, keyboard accelerator, and description.
            </TextBlock>
        </StackPanel>

        <muxcontrols:MenuBar Grid.Row="1" Padding="10">
            <muxcontrols:MenuBarItem Title="File">
            </muxcontrols:MenuBarItem>
            <muxcontrols:MenuBarItem Title="Edit">
                <MenuFlyoutItem x:Name="DeleteFlyoutItem"/>
            </muxcontrols:MenuBarItem>
            <muxcontrols:MenuBarItem Title="Help">
            </muxcontrols:MenuBarItem>
        </muxcontrols:MenuBar>

        <ListView x:Name="ListViewRight" Grid.Row="2" 
                  Loaded="ListView_Loaded" 
                  IsItemClickEnabled="True" 
                  SelectionMode="Single" 
                  SelectionChanged="ListView_SelectionChanged" 
                  ItemContainerStyle="{StaticResource HorizontalSwipe}">
            <ListView.ItemTemplate>
                <DataTemplate x:DataType="local:ListItemData">
                    <UserControl PointerEntered="ListViewSwipeContainer_PointerEntered" 
                                 PointerExited="ListViewSwipeContainer_PointerExited">
                        <UserControl.ContextFlyout>
                            <MenuFlyout>
                                <MenuFlyoutItem 
                                    Command="{x:Bind Command}" 
                                    CommandParameter="{x:Bind Text}" />
                            </MenuFlyout>
                        </UserControl.ContextFlyout>
                        <Grid AutomationProperties.Name="{x:Bind Text}">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="HoveringStates">
                                    <VisualState x:Name="HoverButtonsHidden" />
                                    <VisualState x:Name="HoverButtonsShown">
                                        <VisualState.Setters>
                                            <Setter Target="HoverButton.Visibility" 
                                                    Value="Visible" />
                                        </VisualState.Setters>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <SwipeControl x:Name="ListViewSwipeContainer" >
                                <SwipeControl.RightItems>
                                    <SwipeItems Mode="Execute">
                                        <SwipeItem x:Name="DeleteSwipeItem" 
                                                   Background="Red" 
                                                   Command="{x:Bind Command}" 
                                                   CommandParameter="{x:Bind Text}"/>
                                    </SwipeItems>
                                </SwipeControl.RightItems>
                                <Grid VerticalAlignment="Center">
                                    <TextBlock Text="{x:Bind Text}" 
                                               Margin="10" 
                                               FontSize="18" 
                                               HorizontalAlignment="Left" 
                                               VerticalAlignment="Center"/>
                                    <AppBarButton x:Name="HoverButton" 
                                                  IsTabStop="False" 
                                                  HorizontalAlignment="Right" 
                                                  Visibility="Collapsed" 
                                                  Command="{x:Bind Command}" 
                                                  CommandParameter="{x:Bind Text}"/>
                                </Grid>
                            </SwipeControl>
                        </Grid>
                    </UserControl>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</Page>

코드 숨김Code-behind

  1. 먼저, ListView의 각 ListViewItem에 대한 텍스트 문자열과 ICommand를 포함하는 ListItemData 클래스를 정의합니다.First, we define a ListItemData class that contains a text string and ICommand for each ListViewItem in our ListView.
public class ListItemData
{
    public String Text { get; set; }
    public ICommand Command { get; set; }
}
  1. MainPage 클래스에서 ListView ItemTemplateDataTemplate에 대한 ListItemData 개체 컬렉션을 정의합니다.In the MainPage class, we define a collection of ListItemData objects for the DataTemplate of the ListView ItemTemplate. 그런 다음, 처음 5개 항목의 컬렉션으로 채웁니다(텍스트 및 연결된 StandardUICommand Delete를 사용하여).We then populate it with an initial collection of five items (with text and associated StandardUICommand Delete).
/// <summary>
/// ListView item collection.
/// </summary>
ObservableCollection<ListItemData> collection = 
    new ObservableCollection<ListItemData>();

/// <summary>
/// Handler for the layout Grid control load event.
/// </summary>
/// <param name="sender">Source of the control loaded event</param>
/// <param name="e">Event args for the loaded event</param>
private void ControlExample_Loaded(object sender, RoutedEventArgs e)
{
    // Create the standard Delete command.
    var deleteCommand = new StandardUICommand(StandardUICommandKind.Delete);
    deleteCommand.ExecuteRequested += DeleteCommand_ExecuteRequested;

    DeleteFlyoutItem.Command = deleteCommand;

    for (var i = 0; i < 5; i++)
    {
        collection.Add(
            new ListItemData {
                Text = "List item " + i.ToString(),
                Command = deleteCommand });
    }
}

/// <summary>
/// Handler for the ListView control load event.
/// </summary>
/// <param name="sender">Source of the control loaded event</param>
/// <param name="e">Event args for the loaded event</param>
private void ListView_Loaded(object sender, RoutedEventArgs e)
{
    var listView = (ListView)sender;
    // Populate the ListView with the item collection.
    listView.ItemsSource = collection;
}
  1. 다음으로, ICommand ExecuteRequested 처리기를 정의하고 항목 삭제 명령을 구현합니다.Next, we define the ICommand ExecuteRequested handler where we implement the item delete command.
/// <summary>
/// Handler for the Delete command.
/// </summary>
/// <param name="sender">Source of the command event</param>
/// <param name="e">Event args for the command event</param>
private void DeleteCommand_ExecuteRequested(
    XamlUICommand sender, ExecuteRequestedEventArgs args)
{
    // If possible, remove specfied item from collection.
    if (args.Parameter != null)
    {
        foreach (var i in collection)
        {
            if (i.Text == (args.Parameter as string))
            {
                collection.Remove(i);
                return;
            }
        }
    }
    if (ListViewRight.SelectedIndex != -1)
    {
        collection.RemoveAt(ListViewRight.SelectedIndex);
    }
}
  1. 마지막으로, PointerEntered, PointerExitedSelectionChanged 이벤트를 포함하여 다양한 ListView 이벤트에 대한 처리기를 정의합니다.Finally, we define handlers for various ListView events, including PointerEntered, PointerExited, and SelectionChanged events. 포인터 이벤트 처리기는 각 항목의 삭제 단추를 표시하거나 숨기는 데 사용됩니다.The pointer event handlers are used to show or hide the Delete button for each item.
/// <summary>
/// Handler for the ListView selection changed event.
/// </summary>
/// <param name="sender">Source of the selection changed event</param>
/// <param name="e">Event args for the selection changed event</param>
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (ListViewRight.SelectedIndex != -1)
    {
        var item = collection[ListViewRight.SelectedIndex];
    }
}

/// <summary>
/// Handler for the pointer entered event.
/// Displays the delete item "hover" buttons.
/// </summary>
/// <param name="sender">Source of the pointer entered event</param>
/// <param name="e">Event args for the pointer entered event</param>
private void ListViewSwipeContainer_PointerEntered(
    object sender, PointerRoutedEventArgs e)
{
    if (e.Pointer.PointerDeviceType == 
        Windows.Devices.Input.PointerDeviceType.Mouse || 
        e.Pointer.PointerDeviceType == 
        Windows.Devices.Input.PointerDeviceType.Pen)
    {
        VisualStateManager.GoToState(
            sender as Control, "HoverButtonsShown", true);
    }
}

/// <summary>
/// Handler for the pointer exited event.
/// Hides the delete item "hover" buttons.
/// </summary>
/// <param name="sender">Source of the pointer exited event</param>
/// <param name="e">Event args for the pointer exited event</param>

private void ListViewSwipeContainer_PointerExited(
    object sender, PointerRoutedEventArgs e)
{
    VisualStateManager.GoToState(
        sender as Control, "HoverButtonsHidden", true);
}

XamlUICommand 클래스를 사용하는 명령 환경Command experiences using the XamlUICommand class

StandardUICommand 클래스에 정의되지 않은 명령을 만들어야 하거나 명령의 모양을 보다 정교하게 제어하려는 경우 XamlUiCommand 클래스는 ICommand 인터페이스에서 파생되어 UI 및 사용자 지정 명령의 동작을 신속하게 정의할 수 있는 다양한 UI 속성(예: 아이콘, 레이블, 설명, 바로 가기 키), 메서드 및 이벤트를 추가합니다.If you need to create a command that isn't defined by the StandardUICommand class, or you'd like more control over the command appearance, the XamlUiCommand class derives from the ICommand interface, adding various UI properties (such as an icon, label, description, and keyboard shortcuts), methods, and events to quickly define the UI and behavior of a custom command.

XamlUICommand를 사용하면 개별 속성을 설정하지 않고 아이콘, 레이블, 설명, 바로 가기 키(액세스 키 및 키보드 가속기 둘 다) 같은 컨트롤 바인딩을 통해 UI를 지정할 수 있습니다.XamlUICommand lets you specify UI through the control binding, such as an icon, label, description, and keyboard shortcuts (both an access key and a keyboard accelerator), without setting the individual properties.

예제Example

XamlUICommand 샘플

XamlUICommandSampleXamlUICommandSample

이 예제의 코드 다운로드Download the code for this example
UWP 명령 샘플(XamlUICommand)UWP commanding sample (XamlUICommand)

이 예제에서는 이전 StandardUICommand 예제의 삭제 기능을 공유하지만, XamlUICommand 클래스를 사용하여 개발자 고유의 글꼴, 아이콘, 레이블, 키보드 가속기 및 설명으로 사용자 지정 삭제 명령을 정의하는 방법을 보여줍니다.This example shares the Delete functionality of the previous StandardUICommand example, but shows how the XamlUICommand class lets you define a custom delete command with your own font icon, label, keyboard accelerator, and description. StandardUICommand 예제와 마찬가지로, XamlUICommand 클래스를 통해 구현된 항목 삭제 명령으로 기본 ListView를 개선하고 MenuBar, 살짝 밀기 컨트롤, 호버 단추 및 상황에 맞는 메뉴를 사용하여 다양한 입력 형식에 맞게 사용자 환경을 최적화합니다.Like the StandardUICommand example, we enhance a basic ListView with a Delete item command implemented through the XamlUICommand class, while optimizing the user experience for a variety of input types using a MenuBar, Swipe control, hover buttons, and context menu.

이전 섹션의 StandardUICommand 예제와 마찬가지로, 많은 플랫폼 컨트롤이 XamlUICommand 속성을 내부적으로 사용합니다.Many platform controls use the XamlUICommand properties under the covers, just like our StandardUICommand example in the previous section.

참고

이 샘플에는 Microsoft Windows UI 라이브러리의 일부인 Microsoft.UI.Xaml.Controls NuGet 패키지가 필요합니다.This sample requires the Microsoft.UI.Xaml.Controls NuGet package, a part of the Microsoft Windows UI Library.

Xaml:Xaml:

샘플 UI에는 5개 항목의 ListView가 포함되어 있습니다.The sample UI includes a ListView of five items. 사용자 지정 XamlUICommand 삭제는 MenuBarItem, SwipeItem, AppBarButtonContextFlyout 메뉴에 바인딩됩니다.The custom XamlUICommand Delete is bound to a MenuBarItem, a SwipeItem, an AppBarButton, and ContextFlyout menu.

<Page
    x:Class="XamlUICommand_Sample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:XamlUICommand_Sample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:muxcontrols="using:Microsoft.UI.Xaml.Controls"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Page.Resources>
        <XamlUICommand x:Name="CustomXamlUICommand" 
                       ExecuteRequested="DeleteCommand_ExecuteRequested"
                       Description="Custom XamlUICommand" 
                       Label="Custom XamlUICommand">
            <XamlUICommand.IconSource>
                <FontIconSource FontFamily="Wingdings" Glyph="&#x4D;"/>
            </XamlUICommand.IconSource>
            <XamlUICommand.KeyboardAccelerators>
                <KeyboardAccelerator Key="D" Modifiers="Control"/>
            </XamlUICommand.KeyboardAccelerators>
        </XamlUICommand>

        <Style x:Key="HorizontalSwipe" 
               TargetType="ListViewItem" 
               BasedOn="{StaticResource ListViewItemRevealStyle}">
            <Setter Property="Height" Value="70"/>
            <Setter Property="Padding" Value="0"/>
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
            <Setter Property="VerticalContentAlignment" Value="Stretch"/>
            <Setter Property="BorderThickness" Value="0"/>
        </Style>
        
    </Page.Resources>

    <Grid Loaded="ControlExample_Loaded" Name="MainGrid">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        
        <StackPanel Grid.Row="0" 
                    Padding="10" 
                    BorderThickness="0,0,0,1" 
                    BorderBrush="LightBlue"
                    Background="AliceBlue">
            <TextBlock Style="{StaticResource HeaderTextBlockStyle}">
                XamlUICommand sample
            </TextBlock>
            <TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Margin="0,0,0,10">
                This sample shows how to use the XamlUICommand class to 
                share a custom command with consistent user experiences 
                across various controls.
            </TextBlock>
            <TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Margin="0,0,0,0">
                Specifically, we define a custom delete command and add it 
                to a variety of command surfaces, all of which share a common 
                icon, label, keyboard accelerator, and description.
            </TextBlock>
        </StackPanel>

        <muxcontrols:MenuBar Grid.Row="1">
            <muxcontrols:MenuBarItem Title="File">
            </muxcontrols:MenuBarItem>
            <muxcontrols:MenuBarItem Title="Edit">
                <MenuFlyoutItem x:Name="DeleteFlyoutItem" 
                                Command="{StaticResource CustomXamlUICommand}"/>
            </muxcontrols:MenuBarItem>
            <muxcontrols:MenuBarItem Title="Help">
            </muxcontrols:MenuBarItem>
        </muxcontrols:MenuBar>

        <ListView x:Name="ListViewRight" Grid.Row="2" 
                  Loaded="ListView_Loaded" 
                  IsItemClickEnabled="True"
                  SelectionMode="Single" 
                  SelectionChanged="ListView_SelectionChanged" 
                  ItemContainerStyle="{StaticResource HorizontalSwipe}">
            <ListView.ItemTemplate>
                <DataTemplate x:DataType="local:ListItemData">
                    <UserControl PointerEntered="ListViewSwipeContainer_PointerEntered"
                                 PointerExited="ListViewSwipeContainer_PointerExited">
                        <UserControl.ContextFlyout>
                            <MenuFlyout>
                                <MenuFlyoutItem 
                                    Command="{x:Bind Command}" 
                                    CommandParameter="{x:Bind Text}" />
                            </MenuFlyout>
                        </UserControl.ContextFlyout>
                        <Grid AutomationProperties.Name="{x:Bind Text}">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="HoveringStates">
                                    <VisualState x:Name="HoverButtonsHidden" />
                                    <VisualState x:Name="HoverButtonsShown">
                                        <VisualState.Setters>
                                            <Setter Target="HoverButton.Visibility" 
                                                    Value="Visible" />
                                        </VisualState.Setters>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <SwipeControl x:Name="ListViewSwipeContainer">
                                <SwipeControl.RightItems>
                                    <SwipeItems Mode="Execute">
                                        <SwipeItem x:Name="DeleteSwipeItem"
                                                   Background="Red" 
                                                   Command="{x:Bind Command}" 
                                                   CommandParameter="{x:Bind Text}"/>
                                    </SwipeItems>
                                </SwipeControl.RightItems>
                                <Grid VerticalAlignment="Center">
                                    <TextBlock Text="{x:Bind Text}" 
                                               Margin="10" 
                                               FontSize="18" 
                                               HorizontalAlignment="Left"       
                                               VerticalAlignment="Center"/>
                                    <AppBarButton x:Name="HoverButton" 
                                                  IsTabStop="False" 
                                                  HorizontalAlignment="Right" 
                                                  Visibility="Collapsed" 
                                                  Command="{x:Bind Command}" 
                                                  CommandParameter="{x:Bind Text}"/>
                                </Grid>
                            </SwipeControl>
                        </Grid>
                    </UserControl>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</Page>

코드 숨김Code-behind

  1. 먼저, ListView의 각 ListViewItem에 대한 텍스트 문자열과 ICommand를 포함하는 ListItemData 클래스를 정의합니다.First, we define a ListItemData class that contains a text string and ICommand for each ListViewItem in our ListView.
public class ListItemData
{
    public String Text { get; set; }
    public ICommand Command { get; set; }
}
  1. MainPage 클래스에서 ListView ItemTemplateDataTemplate에 대한 ListItemData 개체 컬렉션을 정의합니다.In the MainPage class, we define a collection of ListItemData objects for the DataTemplate of the ListView ItemTemplate. 그런 다음, 처음 5개 항목의 컬렉션으로 채웁니다(텍스트 및 연결된 XamlUICommand를 사용하여).We then populate it with an initial collection of five items (with text and associated XamlUICommand).
ObservableCollection<ListItemData> collection = new ObservableCollection<ListItemData>();

private void ControlExample_Loaded(object sender, RoutedEventArgs e)
{
    for (var i = 0; i < 5; i++)
    {
        collection.Add(
           new ListItemData { Text = "List item " + i.ToString(), Command = CustomXamlUICommand });
    }
}

private void ListView_Loaded(object sender, RoutedEventArgs e)
{
    var listView = (ListView)sender;
    listView.ItemsSource = collection;
}
  1. 다음으로, ICommand ExecuteRequested 처리기를 정의하고 항목 삭제 명령을 구현합니다.Next, we define the ICommand ExecuteRequested handler where we implement the item delete command.
private void DeleteCommand_ExecuteRequested(
   XamlUICommand sender, ExecuteRequestedEventArgs args)
{
    if (args.Parameter != null)
    {
        foreach (var i in collection)
        {
            if (i.Text == (args.Parameter as string))
            {
                collection.Remove(i);
                return;
            }
        }
    }
    if (ListViewRight.SelectedIndex != -1)
    {
        collection.RemoveAt(ListViewRight.SelectedIndex);
    }
}
  1. 마지막으로, PointerEntered, PointerExitedSelectionChanged 이벤트를 포함하여 다양한 ListView 이벤트에 대한 처리기를 정의합니다.Finally, we define handlers for various ListView events, including PointerEntered, PointerExited, and SelectionChanged events. 포인터 이벤트 처리기는 각 항목의 삭제 단추를 표시하거나 숨기는 데 사용됩니다.The pointer event handlers are used to show or hide the Delete button for each item.
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (ListViewRight.SelectedIndex != -1)
    {
        var item = collection[ListViewRight.SelectedIndex];
    }
}

private void ListViewSwipeContainer_PointerEntered(object sender, PointerRoutedEventArgs e)
{
    if (e.Pointer.PointerDeviceType == 
        Windows.Devices.Input.PointerDeviceType.Mouse || 
        e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Pen)
    {
        VisualStateManager.GoToState(sender as Control, "HoverButtonsShown", true);
    }
}

private void ListViewSwipeContainer_PointerExited(object sender, PointerRoutedEventArgs e)
{
    VisualStateManager.GoToState(sender as Control, "HoverButtonsHidden", true);
}

ICommand 인터페이스를 사용하는 명령 환경Command experiences using the ICommand interface

표준 UWP 컨트롤(단추, 목록, 선택, 일정, 예측 텍스트)은 여러 일반 명령 환경을 위한 기초를 제공합니다.Standard UWP controls (button, list, selection, calendar, predictive text) provide the basis for many common command experiences. 컨트롤 형식의 전체 목록은 Windows 앱을 위한 컨트롤 및 패턴을 참조하세요.For a complete list of control types, see Controls and patterns for Windows apps.

체계적인 명령 환경을 지원하는 가장 기본적인 방법은 ICommand 인터페이스 구현을 정의하는 것입니다(C++는 Windows.UI.Xaml.Input.ICommand, C#은 System.Windows.Input.ICommand).The most basic way to support a structured commanding experience is to define an implementation of the ICommand interface (Windows.UI.Xaml.Input.ICommand for C++ or System.Windows.Input.ICommand for C#). 이 ICommand 인스턴스를 단추 같은 컨트롤에 바인딩할 수 있습니다.This ICommand instance can then be bound to controls such as buttons.

참고

경우에 따라 메서드를 Click 이벤트에 바인딩하고 속성을 IsEnabled 속성에 바인딩하는 것이 효과적일 수 있습니다.In some cases, it might be just as efficient to bind a method to the Click event and a property to the IsEnabled property.

예제Example

명령 인터페이스 예제

ICommand 예제ICommand example

이 예제의 코드 다운로드Download the code for this example
UWP 명령 샘플(ICommand)UWP commanding sample (ICommand)

이 기본 예제에서는 단추 클릭, 바로 가기 키, 마우스 휠 회전을 통해 단일 명령을 호출하는 방법을 보여줍니다.In this basic example, we demonstrate how a single command can be invoked with a button click, a keyboard accelerator, and rotating a mouse wheel.

ListView를 두 개 사용합니다. 하나는 5개 항목과 다른 빈 항목 그리고 단추 2개로 채워져 있고 왼쪽에 있는 ListView의 항목을 오른쪽에 있는 ListView로 이동하는 데 사용되며, 다른 하나는 오른쪽에서 왼쪽으로 항목을 이동하는 데 사용됩니다.We use two ListViews, one populated with five items and the other empty, and two buttons, one for moving items from the ListView on the left to the ListView on the right, and the other for moving items from the right to the left. 각 단추는 해당 명령에 바인딩되고(각각 ViewModel.MoveRightCommand 및 ViewModel.MoveLeftCommand), 연결된 ListView의 항목 수에 따라 자동으로 설정/해제됩니다.Each button is bound to a corresponding command (ViewModel.MoveRightCommand and ViewModel.MoveLeftCommand, respectively), and are enabled and disabled automatically based on the number of items in their associated ListView.

다음 XAML 코드는 이 예제의 UI를 정의합니다.The following XAML code defines the UI for our example.

<Page
    x:Class="UICommand1.View.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vm="using:UICommand1.ViewModel"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Page.Resources>
        <vm:OpacityConverter x:Key="opaque" />
    </Page.Resources>

    <Grid Name="ItemGrid"
          Background="AliceBlue"
          PointerWheelChanged="Page_PointerWheelChanged">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="2*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <ListView Grid.Column="0" VerticalAlignment="Center"
                  x:Name="CommandListView" 
                  ItemsSource="{x:Bind Path=ViewModel.ListItemLeft}" 
                  SelectionMode="None" IsItemClickEnabled="False" 
                  HorizontalAlignment="Right">
            <ListView.ItemTemplate>
                <DataTemplate x:DataType="vm:ListItemData">
                    <Grid VerticalAlignment="Center">
                        <AppBarButton Label="{x:Bind ListItemText}">
                            <AppBarButton.Icon>
                                <SymbolIcon Symbol="{x:Bind ListItemIcon}"/>
                            </AppBarButton.Icon>
                        </AppBarButton>
                    </Grid>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        <Grid Grid.Column="1" Margin="0,0,0,0"
              HorizontalAlignment="Center" 
              VerticalAlignment="Center">
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <StackPanel Grid.Row="1">
                <FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" 
                          FontSize="40" Glyph="&#xE893;" 
                          Opacity="{x:Bind Path=ViewModel.ListItemLeft.Count, 
                                        Mode=OneWay, Converter={StaticResource opaque}}"/>
                <Button Name="MoveItemRightButton"
                        Margin="0,10,0,10" Width="120" HorizontalAlignment="Center"
                        Command="{x:Bind Path=ViewModel.MoveRightCommand}">
                    <Button.KeyboardAccelerators>
                        <KeyboardAccelerator 
                            Modifiers="Control" 
                            Key="Add" />
                    </Button.KeyboardAccelerators>
                    <StackPanel>
                        <SymbolIcon Symbol="Next"/>
                        <TextBlock>Move item right</TextBlock>
                    </StackPanel>
                </Button>
                <Button Name="MoveItemLeftButton" 
                            Margin="0,10,0,10" Width="120" HorizontalAlignment="Center"
                            Command="{x:Bind Path=ViewModel.MoveLeftCommand}">
                    <Button.KeyboardAccelerators>
                        <KeyboardAccelerator 
                            Modifiers="Control" 
                            Key="Subtract" />
                    </Button.KeyboardAccelerators>
                    <StackPanel>
                        <SymbolIcon Symbol="Previous"/>
                        <TextBlock>Move item left</TextBlock>
                    </StackPanel>
                </Button>
                <FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" 
                          FontSize="40" Glyph="&#xE892;"
                          Opacity="{x:Bind Path=ViewModel.ListItemRight.Count, 
                                        Mode=OneWay, Converter={StaticResource opaque}}"/>
            </StackPanel>
        </Grid>
        <ListView Grid.Column="2" 
                  x:Name="CommandListViewRight" 
                  VerticalAlignment="Center" 
                  IsItemClickEnabled="False" 
                  SelectionMode="None"
                  ItemsSource="{x:Bind Path=ViewModel.ListItemRight}" 
                  HorizontalAlignment="Left">
            <ListView.ItemTemplate>
                <DataTemplate x:DataType="vm:ListItemData">
                    <Grid VerticalAlignment="Center">
                        <AppBarButton Label="{x:Bind ListItemText}">
                            <AppBarButton.Icon>
                                <SymbolIcon Symbol="{x:Bind ListItemIcon}"/>
                            </AppBarButton.Icon>
                        </AppBarButton>
                    </Grid>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</Page>

다음은 이전 UI의 코드 숨김입니다.Here's the code-behind for the preceding UI.

코드 숨김에서 명령 코드를 포함하는 보기 모델을 연결합니다.In code-behind, we connect to our view model that contains our command code. 또한 마우스 휠의 입력을 처리하는 처리기를 정의합니다. 이 처리기 역시 명령 코드를 연결합니다.In addition, we define a handler for input from the mouse wheel, which also connects our command code.

using Windows.UI.Xaml;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Controls;
using UICommand1.ViewModel;
using Windows.System;
using Windows.UI.Core;

namespace UICommand1.View
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        // Reference to our view model.
        public UICommand1ViewModel ViewModel { get; set; }

        // Initialize our view and view model.
        public MainPage()
        {
            this.InitializeComponent();
            ViewModel = new UICommand1ViewModel();
        }

        /// <summary>
        /// Handle mouse wheel input and assign our
        /// commands to appropriate direction of rotation.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Page_PointerWheelChanged(object sender, PointerRoutedEventArgs e)
        {
            var props = e.GetCurrentPoint(sender as UIElement).Properties;

            // Require CTRL key and accept only vertical mouse wheel movement 
            // to eliminate accidental wheel input.
            if ((Window.Current.CoreWindow.GetKeyState(VirtualKey.Control) != 
                CoreVirtualKeyStates.None) && !props.IsHorizontalMouseWheel)
            {
                bool delta = props.MouseWheelDelta < 0 ? true : false;

                switch (delta)
                {
                    case true:
                        ViewModel.MoveRight();
                        break;
                    case false:
                        ViewModel.MoveLeft();
                        break;
                    default:
                        break;
                }
            }
        }
    }
}

다음은 보기 모델의 코드입니다.Here's the code from our view model

보기 모델에서 앱의 두 명령에 대한 실행 세부 정보를 정의하고, 한 ListView를 채우고, 각 ListView의 항목 수에 따라 추가 UI를 숨기거나 표시하는 불투명도 값 변환기를 제공합니다.Our view model is where we define the execution details for the two commands in our app, populate one ListView, and provide an opacity value converter for hiding or displaying some additional UI based on the item count of each ListView.

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;

namespace UICommand1.ViewModel
{
    /// <summary>
    /// UI properties for our list items.
    /// </summary>
    public class ListItemData
    {
        /// <summary>
        /// Gets and sets the list item content string.
        /// </summary>
        public string ListItemText { get; set; }
        /// <summary>
        /// Gets and sets the list item icon.
        /// </summary>
        public Symbol ListItemIcon { get; set; }
    }

    /// <summary>
    /// View Model that sets up a command to handle invoking the move item buttons.
    /// </summary>
    public class UICommand1ViewModel
    {
        /// <summary>
        /// The command to invoke when the Move item left button is pressed.
        /// </summary>
        public RelayCommand MoveLeftCommand { get; private set; }

        /// <summary>
        /// The command to invoke when the Move item right button is pressed.
        /// </summary>
        public RelayCommand MoveRightCommand { get; private set; }

        // Item collections
        public ObservableCollection<ListItemData> ListItemLeft { get; } = 
           new ObservableCollection<ListItemData>();
        public ObservableCollection<ListItemData> ListItemRight { get; } = 
           new ObservableCollection<ListItemData>();

        public ListItemData listItem;

        /// <summary>
        /// Sets up a command to handle invoking the move item buttons.
        /// </summary>
        public UICommand1ViewModel()
        {
            MoveLeftCommand = 
               new RelayCommand(new Action(MoveLeft), CanExecuteMoveLeftCommand);
            MoveRightCommand = 
               new RelayCommand(new Action(MoveRight), CanExecuteMoveRightCommand);

            LoadItems();
        }

        /// <summary>
        ///  Populate our list of items.
        /// </summary>
        public void LoadItems()
        {
            for (var x = 0; x <= 4; x++)
            {
                listItem = new ListItemData();
                listItem.ListItemText = "Item " + (ListItemLeft.Count + 1).ToString();
                listItem.ListItemIcon = Symbol.Emoji;
                ListItemLeft.Add(listItem);
            }
        }

        /// <summary>
        /// Move left command valid when items present in the list on right.
        /// </summary>
        /// <returns>True, if count is greater than 0.</returns>
        private bool CanExecuteMoveLeftCommand()
        {
            return ListItemRight.Count > 0;
        }

        /// <summary>
        /// Move right command valid when items present in the list on left.
        /// </summary>
        /// <returns>True, if count is greater than 0.</returns>
        private bool CanExecuteMoveRightCommand()
        {
            return ListItemLeft.Count > 0;
        }

        /// <summary>
        /// The command implementation to execute when the Move item right button is pressed.
        /// </summary>
        public void MoveRight()
        {
            if (ListItemLeft.Count > 0)
            {
                listItem = new ListItemData();
                ListItemRight.Add(listItem);
                listItem.ListItemText = "Item " + ListItemRight.Count.ToString();
                listItem.ListItemIcon = Symbol.Emoji;
                ListItemLeft.RemoveAt(ListItemLeft.Count - 1);
                MoveRightCommand.RaiseCanExecuteChanged();
                MoveLeftCommand.RaiseCanExecuteChanged();
            }
        }

        /// <summary>
        /// The command implementation to execute when the Move item left button is pressed.
        /// </summary>
        public void MoveLeft()
        {
            if (ListItemRight.Count > 0)
            {
                listItem = new ListItemData();
                ListItemLeft.Add(listItem);
                listItem.ListItemText = "Item " + ListItemLeft.Count.ToString();
                listItem.ListItemIcon = Symbol.Emoji;
                ListItemRight.RemoveAt(ListItemRight.Count - 1);
                MoveRightCommand.RaiseCanExecuteChanged();
                MoveLeftCommand.RaiseCanExecuteChanged();
            }
        }

        /// <summary>
        /// Views subscribe to this event to get notified of property updates.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Notify subscribers of updates to the named property
        /// </summary>
        /// <param name="propertyName">The full, case-sensitive, name of a property.</param>
        protected void NotifyPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                PropertyChangedEventArgs args = new PropertyChangedEventArgs(propertyName);
                handler(this, args);
            }
        }
    }

    /// <summary>
    /// Convert a collection count to an opacity value of 0.0 or 1.0.
    /// </summary>
    public class OpacityConverter : IValueConverter
    {
        /// <summary>
        /// Converts a collection count to an opacity value of 0.0 or 1.0.
        /// </summary>
        /// <param name="value">The count passed in</param>
        /// <param name="targetType">Ignored.</param>
        /// <param name="parameter">Ignored</param>
        /// <param name="language">Ignored</param>
        /// <returns>1.0 if count > 0, otherwise returns 0.0</returns>
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            return ((int)value > 0 ? 1.0 : 0.0);
        }

        /// <summary>
        /// Not used, converter is not intended for two-way binding. 
        /// </summary>
        /// <param name="value">Ignored</param>
        /// <param name="targetType">Ignored</param>
        /// <param name="parameter">Ignored</param>
        /// <param name="language">Ignored</param>
        /// <returns></returns>
        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }
}

마지막으로, 다음은 ICommand 인터페이스의 구현입니다.Finally, here's our implementation of the ICommand interface

여기서는 ICommand 인터페이스를 구현하고 해당 기능을 다른 개체에 전달하는 명령을 정의합니다.Here, we define a command that implements the ICommand interface and simply relays its functionality to other objects.

using System;
using System.Windows.Input;

namespace UICommand1
{
    /// <summary>
    /// A command whose sole purpose is to relay its functionality 
    /// to other objects by invoking delegates. 
    /// The default return value for the CanExecute method is 'true'.
    /// <see cref="RaiseCanExecuteChanged"/> needs to be called whenever
    /// <see cref="CanExecute"/> is expected to return a different value.
    /// </summary>
    public class RelayCommand : ICommand
    {
        private readonly Action _execute;
        private readonly Func<bool> _canExecute;

        /// <summary>
        /// Raised when RaiseCanExecuteChanged is called.
        /// </summary>
        public event EventHandler CanExecuteChanged;

        /// <summary>
        /// Creates a new command that can always execute.
        /// </summary>
        /// <param name="execute">The execution logic.</param>
        public RelayCommand(Action execute)
            : this(execute, null)
        {
        }

        /// <summary>
        /// Creates a new command.
        /// </summary>
        /// <param name="execute">The execution logic.</param>
        /// <param name="canExecute">The execution status logic.</param>
        public RelayCommand(Action execute, Func<bool> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");
            _execute = execute;
            _canExecute = canExecute;
        }

        /// <summary>
        /// Determines whether this <see cref="RelayCommand"/> can execute in its current state.
        /// </summary>
        /// <param name="parameter">
        /// Data used by the command. If the command does not require 
        /// data to be passed, this object can be set to null.
        /// </param>
        /// <returns>true if this command can be executed; otherwise, false.</returns>
        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute();
        }

        /// <summary>
        /// Executes the <see cref="RelayCommand"/> on the current command target.
        /// </summary>
        /// <param name="parameter">
        /// Data used by the command. If the command does not require 
        /// data to be passed, this object can be set to null.
        /// </param>
        public void Execute(object parameter)
        {
            _execute();
        }

        /// <summary>
        /// Method used to raise the <see cref="CanExecuteChanged"/> event
        /// to indicate that the return value of the <see cref="CanExecute"/>
        /// method has changed.
        /// </summary>
        public void RaiseCanExecuteChanged()
        {
            var handler = CanExecuteChanged;
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }
    }
}

요약Summary

유니버설 Windows 플랫폼은 컨트롤 형식, 디바이스 및 입력 형식에 관계 없이 명령을 공유하고 관리하는 앱을 빌드할 수 있는 강력하고 유연한 명령 시스템을 제공합니다.The Universal Windows Platform provides a robust and flexible commanding system that lets you build apps that share and manage commands across control types, devices, and input types.

Windows 앱의 명령을 빌드할 때 다음 방법을 사용합니다.Use the following approaches when building commands for your Windows apps:

  • XAML/코드 숨김의 이벤트를 수신 대기하고 처리합니다.Listen for and handle events in XAML/code-behind
  • Click 같은 이벤트 처리 메서드에 바인딩Bind to an event handling method such as Click
  • 개발자 고유의 ICommand 구현을 정의Define your own ICommand implementation
  • 미리 정의된 속성 세트에 개발자 고유의 값을 사용하여 XamlUICommand 개체 만들기Create XamlUICommand objects with your own values for a pre-defined set of properties
  • 미리 정의된 플랫폼 속성 및 값 세트를 사용하여 StandardUICommand 개체 만들기Create StandardUICommand objects with a set of pre-defined platform properties and values

다음 단계Next steps

XamlUICommandStandardUICommand 구현을 보여주는 전체 예제는 XAML 컨트롤 갤러리 샘플을 참조하세요.For a complete example that demonstrates a XamlUICommand and StandardUICommand implementation, see the XAML Controls Gallery sample.

참고 항목See also

Windows 앱을 위한 컨트롤 및 패턴Controls and patterns for Windows apps

샘플Samples

토픽 샘플Topic samples

기타 샘플Other samples