Parancsolás Windows-alkalmazásokban StandardUICommand, XamlUICommand és ICommand használatával

Ebben a témakörben a Windows-alkalmazások parancsait ismertetjük. Konkrétan azt tárgyaljuk, hogyan használhatja a XamlUICommand és a StandardUICommand osztályt (az ICommand felülettel együtt) a különböző vezérlőtípusok parancsainak megosztására és kezelésére, függetlenül attól, hogy milyen eszközt és bemeneti típust használ.

Megosztott parancsok gyakori használatát ábrázoló diagram: több felhasználói felület

Parancsok megosztása különböző vezérlők között, eszköztől és bemeneti típustól függetlenül

Fontos API-k

Áttekintés

A parancsokat közvetlenül felhasználói felületi interakciókon keresztül hívhatja meg, például rákattinthat egy gombra, vagy kiválaszthat egy elemet egy helyi menüből. Indirekt módon is meghívhatók olyan beviteli eszközökön keresztül, mint a billentyűzetgyorsító, a kézmozdulat, a beszédfelismerés vagy egy automatizálási/akadálymentességi eszköz. A meghívást követően a parancs kezelhető egy vezérlővel (szövegnavigáció szerkesztési vezérlőben), egy ablakkal (háttérnavigációval) vagy az alkalmazással (kilépés).

A parancsok az alkalmazáson belül egy adott környezetben is működhetnek, például törölhetnek szöveget vagy visszavonhatnak egy műveletet, vagy környezetfüggők lehetnek, például elnémíthatják a hangokat vagy módosíthatják a fényerőt.

Az alábbi képen két parancssori felület látható (egy parancssáv és egy lebegő környezetfüggő CommandBarFlyout), amelyek ugyanazon parancsok egy részét tartalmazzák.

Kibontott parancssáv
Parancssáv

Helyi menü a Microsoft Fényképek gyűjteményében
Helyi menü a Microsoft Fényképek gyűjteményében

Parancs-interakciók

A parancsok meghívását befolyásoló különféle eszközök, bemeneti típusok és felhasználói felület miatt javasoljuk, hogy a parancsokat a lehető legtöbb parancsfelületen keresztül adja ki. Ezek közé tartozhat a pöccintés, a menüsáv, a commandbar, a CommandBarFlyout és a hagyományos helyi menü kombinációja.

Kritikus parancsokhoz használjon bemenetspecifikus gyorsítókat. A bemeneti gyorsítók segítségével a felhasználó gyorsabban hajthatja végre a műveleteket a használt bemeneti eszköztől függően.

Íme néhány gyakori bemenetigyorsító a különböző bemenettípusokhoz:

  • Egérmutató – Egér és toll lebegtető gombok
  • Billentyűparancsok (hozzáférési billentyűk és gyorsítóbillentyűk)
  • Érintés – Húzás
  • Érintés – Húzza le az adatok frissítéséhez

Figyelembe kell vennie a bemeneti típust és a felhasználói élményt, hogy az alkalmazás funkciói univerzálisan hozzáférhetők legyenek. A gyűjtemények (különösen a felhasználó által szerkeszthetők) például általában különböző parancsokat tartalmaznak, amelyeket a bemeneti eszköztől függően meglehetősen eltérően hajtanak végre.

Az alábbi táblázat néhány tipikus gyűjteményparancsot és a parancsok elérhetővé fogadására vonatkozó módszereket mutatja be.

Command Input-agnostic Egérgyorsító Billentyűzetgyorsító Érintésgyorsító
Elem törlése Helyi menü Lebegő gomb DEL billentyű Pöccintés a törléshez
Jelölőelem Helyi menü Lebegő gomb Ctrl+Shift+G Lapozás a jelöléshez
Adatok frissítése Helyi menü N/A F5 billentyű Húzza le a frissítéshez
Elem kedvence Helyi menü Lebegő gomb F, Ctrl+S Pöccintés a kedvenchez

Mindig adjon meg helyi menüt Javasoljuk, hogy az összes releváns környezeti parancsot egy hagyományos helyi menübe vagy a CommandBarFlyoutba foglalja bele, mivel mindkettő támogatott az összes bemeneti típus esetében. Ha például egy parancs csak a mutató rámutatási eseménye során van közzétéve, akkor nem használható érintéses eszközön.

Parancsok Windows-alkalmazásokban

A Windows-alkalmazásokban többféleképpen oszthatja meg és kezelheti a parancskezelési funkciókat. Definiálhat eseménykezelőket a szabványos interakciókhoz, például a Kattintáshoz, kód mögött (ez a felhasználói felület összetettségétől függően meglehetősen nem hatékony lehet), az eseményfigyelőt a szokásos interakciókhoz egy megosztott kezelőhöz kötheti, vagy a vezérlő Command tulajdonságát egy, a parancslogikát leíró ICommand-implementációhoz kötheti.

Ha hatékonyan és minimális kódismétléssel szeretne gazdag és átfogó felhasználói élményt nyújtani a parancsfelületeken, javasoljuk, hogy használja az ebben a témakörben ismertetett parancskötési funkciókat (a standard eseménykezeléshez tekintse meg az egyes eseménytémaköröket).

Ha egy vezérlőt egy megosztott parancserőforráshoz szeretne kötni, saját maga implementálhatja az ICommand interfészeket, vagy létrehozhatja a parancsot a XamlUICommand alaposztályból vagy a StandardUICommand származtatott osztály által meghatározott platformparancsokból.

  • Az ICommand felület (Microsoft.UI.Xaml.Input.ICommand vagy System.Windows.Input.ICommand) lehetővé teszi, hogy teljesen testre szabott, újrafelhasználható parancsokat hozzon létre az alkalmazás egészében.
  • A XamlUICommand ezt a képességet is biztosítja, de leegyszerűsíti a fejlesztést olyan beépített parancstulajdonságok közzétételével, mint a parancs viselkedése, billentyűparancsok (hozzáférési kulcs és gyorsítókulcs), ikon, címke és leírás.
  • A StandardUICommand tovább egyszerűsíti a dolgokat azáltal, hogy lehetővé teszi, hogy előre meghatározott tulajdonságokkal rendelkező standard platformparancsok közül válasszon.

Fontos

A WinUI-alkalmazásokban a parancsok a választott nyelvi keretrendszertől függően vagy a Microsoft.UI.Xaml.Input.ICommand (C++), vagy a System.Windows.Input.ICommand (C#) interfészt megvalósító objektumok.

Parancsélmények a StandardUICommand osztály használatával

A XamlUICommand osztályból származó (Microsoft.UI.Xaml.Input.ICommand-ból származó C++ esetén, illetve System.Windows.Input.ICommand-ból származó C# esetén) StandardUICommand osztály a platform szabványos parancsainak egy olyan készletét teszi elérhetővé, amely előre definiált tulajdonságokkal rendelkezik, például ikonnal, billentyűparanccsal és leírással.

A StandardUICommand gyors és konzisztens módot kínál az olyan gyakori parancsok definiálására, mint például Save a .Delete Mindössze annyit kell tennie, hogy megadja a végrehajtási és canExecute függvényeket.

Example

StandardUICommand példa

StandardUICommandSample

Ebben a példában azt mutatjuk be, hogyan fejleszthet alapszintű ListView-t a StandardUICommand osztályon keresztül implementált Delete elemparancsokkal, miközben a felhasználói élményt számos beviteli típushoz optimalizálhatja a Menüsáv, a Pöccintés vezérlő, a rámutatás gombjai és a helyi menü használatával.

Xaml:

A minta felhasználói felület öt elemből álló ListView-t tartalmaz. A StandardUICommand törlése menüBarItem, SwipeItem, AppBarButton és ContextFlyout menühöz van kötve.

<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>

Kód mögött

  1. Először meghatározunk egy osztályt ListItemData , amely szöveges sztringet és ICommand értéket tartalmaz a ListView minden ListViewItem eleméhez.
public class ListItemData
{
    public String Text { get; set; }
    public ICommand Command { get; set; }
}
  1. A MainPage osztályban a ListItemDataItemTemplateDataTemplate objektumgyűjteményét definiáljuk. Ezután feltöltjük egy öt elemből álló kezdeti gyűjteménysel (szöveggel és a hozzá tartozó StandardUICommand Deletetel).
/// <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. Ezután definiáljuk az ICommand ExecuteRequested kezelőt, ahol implementáljuk az elemtörlés parancsot.
/// <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 specified 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. Végül definiáljuk a különböző ListView-események kezelőit, például a PointerEntered, a PointerExited és a SelectionChanged eseményeket. A mutató eseménykezelői az egyes elemek Törlés gombjának megjelenítésére vagy elrejtésére szolgálnak.
/// <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);
}

Parancsélmények a XamlUICommand osztály használatával

Ha olyan parancsot kell létrehoznia, amelyet nem a StandardUICommand osztály határoz meg, vagy jobban szeretné szabályozni a parancs megjelenését, a XamlUICommand osztály az ICommand felületről származik, és különböző felhasználói felületi tulajdonságokat (például ikont, címkét, leírást és billentyűparancsokat), metódusokat és eseményeket ad hozzá az egyéni parancsok felhasználói felületének és viselkedésének gyors meghatározásához.

A XamlUICommand lehetővé teszi a felhasználói felület megadását a vezérlőkötésen keresztül, például egy ikont, címkét, leírást és billentyűparancsot (mind a hozzáférési kulcsot, mind a billentyűzetgyorsítót) az egyes tulajdonságok megadása nélkül.

Example

XamlUICommand minta

XamlUICommandSample

A példa kódjának letöltése (XamlUICommand) Számos platformvezérlő használja a XamlUICommand tulajdonságokat a borítók alatt, ugyanúgy, mint az előző szakaszban bemutatott StandardUICommand-példánk.

Xaml:

A minta felhasználói felület öt elemből álló ListView-t tartalmaz. Az egyéni XamlUICommand CustomXamlUICommand a MenuBarItem, a SwipeItem, az AppBarButton és a ContextFlyout menühöz van kötve.

<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>

Kód mögött

  1. Először meghatározunk egy osztályt ListItemData , amely szöveges sztringet és ICommand értéket tartalmaz a ListView minden ListViewItem eleméhez.
public class ListItemData
{
    public String Text { get; set; }
    public ICommand Command { get; set; }
}
  1. A MainPage osztályban a ListItemDataItemTemplateDataTemplate objektumgyűjteményét definiáljuk. Ezután feltöltjük egy öt elemből álló kezdeti gyűjteménysel (szöveggel és társított XamlUICommandtal).
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. Ezután definiáljuk az ICommand ExecuteRequested kezelőt, ahol implementáljuk az elemtörlés parancsot.
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. Végül definiáljuk a különböző ListView-események kezelőit, például a PointerEntered, a PointerExited és a SelectionChanged eseményeket. A mutató eseménykezelői az egyes elemek Törlés gombjának megjelenítésére vagy elrejtésére szolgálnak.
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);
}

Parancsélmények az ICommand felület használatával

A szabványos WinUI-vezérlők (gomb, lista, kijelölés, naptár, prediktív szöveg) számos gyakori parancsélmény alapjait biztosítják. A vezérlőtípusok teljes listáját a Windows-alkalmazások vezérlői és mintái című témakörben találja.

A strukturált parancsolás támogatásának legalapvetőbb módja az ICommand felület implementációjának meghatározása (Microsoft. UI. Xaml.Input.ICommand for C++ vagy System.Windows. Input.ICommand for C#). Ezt az ICommand-példányt ezután vezérlőkhöz, például gombokhoz lehet kötni.

Megjegyzés:

Bizonyos esetekben ugyanolyan hatékony lehet egy metódus kötése a Click eseményhez és egy tulajdonsághoz az IsEnabled tulajdonsághoz.

Example

Példa a parancssori felületre

Példa az ICommand-ra

Ebben az alapvető példában bemutatjuk, hogyan hívható meg egyetlen parancs egy gombkattintással, egy billentyűzetgyorsítóval és egy egérkerék elforgatásával.

<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>

Itt látható az előző felhasználói felület mögötti kód.

A „code-behind”-ban csatlakozunk a parancskódot tartalmazó nézetmodellhez. Emellett meghatározunk egy kezelőt az egérkerékről érkező bemenethez, amely a parancskódot is összeköti.

using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Controls;
using UICommand1.ViewModel;
using Windows.System;
using Windows.UI.Core; // for CoreVirtualKeyStates
using Microsoft.UI.Input; // for InputKeyboardSource

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 ((Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(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;
                }
            }
        }
    }
}

Íme a nézetmodell kódja

A nézetmodellben definiáljuk az alkalmazás két parancsának végrehajtási adatait, feltöltünk egy ListView-t, és biztosítunk egy átlátszatlansági értékkonvertert, amely elrejti vagy megjelenít néhány további felhasználói felületet az egyes ListView-elemek száma alapján.

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Microsoft.UI.Xaml.Controls;
using Microsoft.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();
        }
    }
}

Végül pedig az ICommand felület implementálása

Itt meghatározunk egy parancsot, amely implementálja az ICommand felületet, és egyszerűen továbbítja annak funkcióit más objektumoknak.

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);
            }
        }
    }
}

Összefoglalás

A WinUI robusztus és rugalmas parancskezelő rendszert biztosít, amellyel olyan alkalmazásokat hozhat létre, amelyek vezérlőtípusok, eszközök és bemeneti típusok parancsait osztják meg és kezelik.

Windows-alkalmazások parancsainak létrehozásakor használja az alábbi módszereket:

  • Események figyelése és kezelése az XAML-ben/kód mögött
  • Kötés egy eseménykezelési módszerhez, például a Kattintáshoz
  • XamlUICommand objektumok létrehozása saját értékekkel előre definiált tulajdonságokhoz
  • StandardUICommand objektumok létrehozása előre definiált platformtulajdonságokkal és értékekkel

Következő lépések

Nyissa meg a WinUI 3 Katalógus alkalmazást, és tekintse meg a XamlUICommand működését

Lásd még

Vezérlők és minták Windows-alkalmazásokhoz

Samples

Témakörminták

Egyéb minták