Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In diesem Thema beschreiben wir die Befehle in Windows-Anwendungen. Insbesondere wird erläutert, wie Sie die XamlUICommand - und StandardUICommand-Klassen (zusammen mit der ICommand-Schnittstelle) zum Freigeben und Verwalten von Befehlen über verschiedene Steuerelementtypen hinweg verwenden können, unabhängig vom verwendeten Geräte- und Eingabetyp.
Freigeben von Befehlen über verschiedene Steuerelemente hinweg, unabhängig vom Geräte- und Eingabetyp
Wichtige APIs
Überblick
Befehle können direkt über UI-Interaktionen aufgerufen werden, z. B. durch Klicken auf eine Schaltfläche oder auswählen eines Elements aus einem Kontextmenü. Sie können auch indirekt über ein Eingabegerät aufgerufen werden, wie eine Tastenkombination, eine Geste, Spracherkennung oder ein Automatisierungs- oder Barrierefreiheitstool. Nach dem Aufrufen kann der Befehl von einem Steuerelement (Textnavigation in einem Bearbeitungssteuerelement), einem Fenster (Rückwärtsnavigation) oder der Anwendung (Beenden) behandelt werden.
Befehle können in Ihrer App in einem bestimmten Kontext ausgeführt werden, z. B. das Löschen von Text oder das Rückgängigmachen einer Aktion, oder sie können kontextfrei sein, z. B. Das Stummschalten von Audio oder das Anpassen der Helligkeit.
Die folgende Abbildung zeigt zwei Befehlsschnittstellen (eine CommandBar und eine unverankerte kontextbezogene CommandBarFlyout), die einige der gleichen Befehle gemeinsam verwenden.
Befehlsleiste
Kontextmenü in der Microsoft Fotos-Galerie
Befehlsinteraktionen
Aufgrund der Vielzahl von Geräten, Eingabetypen und Benutzeroberflächen, die beeinflussen können, wie ein Befehl aufgerufen wird, empfehlen wir, Ihre Befehle über möglichst viele Befehlsoberflächen zugänglich zu machen. Dazu gehören eine Kombination aus Wisch,MenuBar, CommandBar, CommandBarFlyout und herkömmlichem Kontextmenü.
Verwenden Sie für wichtige Befehle eingabespezifische Tastenkombinationen. Mithilfe von Eingabebeschleunigern können Benutzer Aktionen je nach verwendeten Eingabegerät schneller ausführen.
Im Folgenden finden Sie einige allgemeine Eingabebeschleuniger für verschiedene Eingabetypen:
- Zeiger - Maus- und Stift-Hover-Schaltflächen
- Tastatur – Tastenkombinationen (Zugriffstasten und Schnelltasten)
- Toucheingabe – Wischen
- Toucheingabe – Ziehen, um Daten zu aktualisieren
Sie müssen den Eingabetyp und die Benutzererfahrung berücksichtigen, um die Funktionalität Ihrer Anwendung universell zugänglich zu machen. Beispielsweise enthalten Sammlungen (insbesondere bearbeitbare Auflistungen) in der Regel eine Vielzahl bestimmter Befehle, die je nach Eingabegerät ganz anders ausgeführt werden.
In der folgenden Tabelle sind einige typische Sammlungsbefehle und Methoden zum Verfügbarmachen dieser Befehle aufgeführt.
| Command | Eingabeagnostisch | Mausbeschleuniger | Tastenkürzel | Touch-Beschleuniger |
|---|---|---|---|---|
| Element löschen | Kontextmenü | Hover-Schaltfläche | DEL-Taste | Zum Löschen wischen |
| Markierungselement | Kontextmenü | Hover-Schaltfläche | STRG+UMSCHALT+G | Zum Markieren wischen |
| Aktualisieren von Daten | Kontextmenü | N/A | F5-Taste | Aktualisierung durch Ziehen |
| Element als Favorit festlegen | Kontextmenü | Hover-Schaltfläche | F, STRG+S | Zum Favoriten wischen |
Immer ein Kontextmenü bereitstellen Es wird empfohlen, alle relevanten Kontextbefehle in ein herkömmliches Kontextmenü oder CommandBarFlyout einzugeben, da beide für alle Eingabetypen unterstützt werden. Wenn z. B. ein Befehl nur während eines Zeiger-Hoverereignisses verfügbar gemacht wird, kann er nicht auf einem gerät mit Toucheingabe verwendet werden.
Befehle in Windows-Anwendungen
Es gibt einige Möglichkeiten, Befehlsfunktionen in einer Windows-Anwendung freizugeben und zu verwalten. Sie können Ereignishandler für Standardinteraktionen wie Click in CodeBehind definieren (dies kann je nach Komplexität der Benutzeroberfläche ineffizient sein), Sie können Ereignislistener für Standardinteraktionen an einen freigegebenen Handler binden oder die Command-Eigenschaft des Steuerelements an eine ICommand-Implementierung binden, die die Befehlslogik beschreibt.
Um umfassende und reichhaltige Benutzererfahrungen effizient und mit minimaler Code-Duplizierung bereitzustellen, empfehlen wir die Verwendung der in diesem Thema beschriebenen Befehlsbindungsfunktionen (für die Standardereignisbehandlung siehe Einzelthemen zu den Ereignissen).
Wenn Sie ein Steuerelement an eine freigegebene Befehlsressource binden möchten, können Sie die ICommand-Schnittstellen selbst implementieren, oder Sie können den Befehl entweder aus der XamlUICommand-Basisklasse oder aus einem der plattformüblich definierten Plattformbefehle erstellen, die von der von der von standardUICommand abgeleiteten Klasse definiert werden.
- Über die ICommand-Schnittstelle (Windows.UI.Xaml.Input.ICommand oder System.Windows.Input.ICommand) können Sie in Ihrer App vollständig angepasste, wiederverwendbare Befehle erstellen.
- XamlUICommand bietet diese Funktion auch, vereinfacht aber die Entwicklung, indem es eine Reihe integrierter Befehlseigenschaften wie das Befehlsverhalten, Tastenkombinationen (Zugriffstaste und Beschleunigertaste), Symbol, Bezeichnung und Beschreibung bereitstellt.
- StandardUICommand vereinfacht die Dinge weiter, indem Sie aus einer Reihe von Standardplattformbefehlen mit vordefinierten Eigenschaften auswählen können.
Von Bedeutung
In UWP-Anwendungen sind Befehle implementierungen entweder der Windows.UI.Xaml.Input.ICommand (C++) oder der System.Windows.Input.ICommand (C#)-Schnittstelle, je nach ausgewähltem Sprachframework.
Erfahrungen mit Befehlen mithilfe der StandardUICommand-Klasse
Abgeleitet von XamlUICommand (abgeleitet von Windows.UI.Xaml.Input.ICommand für C++ oder System.Windows.Input.ICommand für C#), macht die StandardUICommand-Klasse eine Reihe von Standardplattformbefehlen mit vordefinierten Eigenschaften wie Symbol, Zugriffstaste und Beschreibung verfügbar.
Ein StandardUICommand bietet eine schnelle und konsistente Möglichkeit zum Definieren allgemeiner Befehle wie Save z. B. oder Delete. Sie müssen nur die execute- und canExecute-Funktionen bereitstellen.
Example
StandardUICommandSample
| Code für dieses Beispiel herunterladen |
|---|
| UWP-Befehlsbeispiel (StandardUICommand) |
In diesem Beispiel wird gezeigt, wie Sie ein einfaches ListView-Steuerelement mit einem über die StandardUICommand-Klasse implementierten Befehl "Element löschen" verbessern und gleichzeitig die Benutzererfahrung für eine Vielzahl von Eingabetypen mithilfe einer Menüleiste, eines Wischen-Steuerelements , der Daraufzeigen-Schaltflächen und des Kontextmenüs optimieren.
Hinweis
In diesem Beispiel ist das NuGet-Paket "Microsoft.UI.Xaml.Controls", ein Teil von WinUI 2, erforderlich.
Xaml:
Die Beispiel-UI enthält eine ListView von fünf Elementen. Der Delete StandardUICommand ist an ein MenuBarItem-Element, ein SwipeItem-Element, ein AppBarButton- und ContextFlyout-Menü gebunden.
<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>
CodeBehind
- Zunächst definieren wir eine
ListItemDataKlasse, die eine Textzeichenfolge und ICommand für jedes ListViewItem-Objekt in unserer ListView enthält.
public class ListItemData
{
public String Text { get; set; }
public ICommand Command { get; set; }
}
- In der MainPage-Klasse definieren wir eine Auflistung von
ListItemDataObjekten für die DataTemplate der ListViewItemTemplate. Anschließend füllen wir es mit einer anfänglichen Sammlung von fünf Elementen (mit Text und zugeordneter StandardUICommand Delete) auf.
/// <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;
}
- Als Nächstes definieren wir den ICommand ExecuteRequested-Handler, in dem der Elementlöschbefehl implementiert wird.
/// <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);
}
}
- Schließlich definieren wir Handler für verschiedene ListView-Ereignisse, einschließlich PointerEntered-, PointerExited- und SelectionChanged-Ereignisse . Die Zeigerereignishandler werden verwendet, um die Schaltfläche "Löschen" für jedes Element ein- oder auszublenden.
/// <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);
}
Befehlsinteraktionen mit der XamlUICommand-Klasse
Wenn Sie einen Befehl erstellen müssen, der nicht von der StandardUICommand-Klasse definiert wird, oder Sie mehr Kontrolle über die Befehlsdarstellung wünschen, wird die XamlUICommand-Klasse von der ICommand-Schnittstelle abgeleitet, verschiedene UI-Eigenschaften (z. B. ein Symbol, eine Bezeichnung, eine Beschreibung und Tastenkombinationen), Methoden und Ereignisse hinzugefügt, um die Benutzeroberfläche und das Verhalten eines benutzerdefinierten Befehls schnell zu definieren.
Mit XamlUICommand können Sie Benutzeroberflächenkomponenten durch die Anbindung des Steuerelements festlegen, z. B. ein Symbol, eine Bezeichnung, eine Beschreibung und Tastenkürzel (sowohl eine Zugriffstaste als auch einen Tastaturbeschleuniger), ohne die einzelnen Eigenschaften festzulegen.
Example
XamlUICommandSample
| Code für dieses Beispiel herunterladen |
|---|
| UWP-Befehlsbeispiel (XamlUICommand) |
In diesem Beispiel wird die Delete-Funktionalität des vorherigen StandardUICommand-Beispiels freigegeben, aber es wird gezeigt, wie Sie mit der XamlUICommand-Klasse einen benutzerdefinierten Löschbefehl mit Ihrem eigenen Schriftartsymbol, Bezeichnung, Tastenkombination und Beschreibung definieren können. Wie im Beispiel "StandardUICommand " verbessern wir ein einfaches ListView-Steuerelement mit einem Befehl "Element löschen", der über die XamlUICommand-Klasse implementiert wird, während die Benutzeroberfläche für eine Vielzahl von Eingabetypen mithilfe einer Menüleiste, Wisch-Steuerelement , Hoverschaltflächen und Kontextmenüs optimiert wird.
Viele Plattformsteuerelemente verwenden die XamlUICommand-Eigenschaften im Hintergrund, genau wie unser StandardUICommand-Beispiel im vorherigen Abschnitt.
Hinweis
In diesem Beispiel ist das NuGet-Paket "Microsoft.UI.Xaml.Controls", ein Teil von WinUI 2, erforderlich.
Xaml:
Die Beispiel-UI enthält eine ListView von fünf Elementen. Der benutzerdefinierte XamlUICommand CustomXamlUICommand ist an ein MenuBarItem-Element, ein SwipeItem-Element, ein AppBarButton- und ContextFlyout-Menü gebunden.
<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="M"/>
</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>
CodeBehind
- Zunächst definieren wir eine
ListItemDataKlasse, die eine Textzeichenfolge und ICommand für jedes ListViewItem-Objekt in unserer ListView enthält.
public class ListItemData
{
public String Text { get; set; }
public ICommand Command { get; set; }
}
- In der MainPage-Klasse definieren wir eine Auflistung von
ListItemDataObjekten für die DataTemplate der ListViewItemTemplate. Anschließend füllen wir sie mit einer anfänglichen Sammlung von fünf Elementen (mit Text und zugeordneter XamlUICommand) auf.
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;
}
- Als Nächstes definieren wir den ICommand ExecuteRequested-Handler, in dem der Elementlöschbefehl implementiert wird.
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);
}
}
- Schließlich definieren wir Handler für verschiedene ListView-Ereignisse, einschließlich PointerEntered-, PointerExited- und SelectionChanged-Ereignisse . Die Zeigerereignishandler werden verwendet, um die Schaltfläche "Löschen" für jedes Element ein- oder auszublenden.
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);
}
Befehlsfunktionen mithilfe der ICommand-Schnittstelle
Standard-UWP-Steuerelemente (Schaltfläche, Liste, Auswahl, Kalender, Vorhersagetext) bieten die Grundlage für viele gängige Befehlsfunktionen. Eine vollständige Liste der Steuerelementtypen finden Sie unter "Steuerelemente und Muster für Windows-Apps".
Die einfachste Möglichkeit zur Unterstützung einer strukturierten Befehlsoberfläche besteht darin, eine Implementierung der ICommand-Schnittstelle (Windows.UI.Xaml.Input.ICommand für C++ oder System.Windows.Input.ICommand für C#) zu definieren. Diese ICommand-Instanz kann dann an Steuerelemente wie Schaltflächen gebunden werden.
Hinweis
In einigen Fällen kann es genauso effizient sein, eine Methode an das Click-Ereignis und eine Eigenschaft an die IsEnabled-Eigenschaft zu binden.
Example
Beispiel für ICommand
| Code für dieses Beispiel herunterladen |
|---|
| UWP-Befehlsbeispiel (ICommand) |
In diesem einfachen Beispiel wird veranschaulicht, wie ein einzelner Befehl mit einem Klick auf eine Schaltfläche, einer Tastenkombination und einem Drehen eines Mausrads aufgerufen werden kann.
Wir verwenden zwei ListViews, eine mit fünf Elementen und die andere leere, und zwei Schaltflächen, eine zum Verschieben von Elementen aus der ListView auf der linken Seite zur ListView auf der rechten Seite und die andere zum Verschieben von Elementen von rechts nach links. Jeder Button ist an einen entsprechenden Befehl (ViewModel.MoveRightCommand bzw. ViewModel.MoveLeftCommand) gebunden und wird basierend auf der Anzahl der Elemente in der zugeordneten ListView automatisch aktiviert und deaktiviert.
Der folgende XAML-Code definiert die Benutzeroberfläche für unser Beispiel.
<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=""
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=""
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>
Hier sehen Sie den CodeBehind für die vorherige Benutzeroberfläche.
Im CodeBehind stellen wir eine Verbindung mit unserem Ansichtsmodell her, das unseren Befehlscode enthält. Darüber hinaus definieren wir einen Handler für eingaben aus dem Mausrad, der auch unseren Befehlscode verbindet.
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;
}
}
}
}
}
Hier sehen Sie den Code aus unserem Ansichtsmodell.
In unserem Ansichtsmodell definieren wir die Ausführungsdetails für die beiden Befehle in unserer App, füllen ein ListView-Element und stellen einen Opacity-Wertkonverter zum Ausblenden oder Anzeigen einiger zusätzlicher UI basierend auf der Elementanzahl der einzelnen ListView bereit.
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();
}
}
}
Schließlich sehen Sie hier unsere Implementierung der ICommand-Schnittstelle.
Hier definieren wir einen Befehl, der die ICommand-Schnittstelle implementiert und einfach seine Funktionalität an andere Objekte weitergibt.
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);
}
}
}
}
Zusammenfassung
Die universelle Windows-Plattform bietet ein robustes und flexibles Befehlssystem, mit dem Sie Apps erstellen können, die Befehle über Steuerelementtypen, Geräte und Eingabetypen hinweg freigeben und verwalten.
Verwenden Sie beim Erstellen von Befehlen für Ihre Windows-Apps die folgenden Ansätze:
- Überwachen und Behandeln von Ereignissen in XAML/CodeBehind
- Binden an eine Ereignisbehandlungsmethode wie Click
- Definieren Ihrer eigenen ICommand-Implementierung
- Erstellen von XamlUICommand-Objekten mit eigenen Werten für einen vordefinierten Eigenschaftensatz
- Erstellen von StandardUICommand-Objekten mit einer Reihe vordefinierter Plattformeigenschaften und -werte
Nächste Schritte
Ein vollständiges Beispiel, das eine XamlUICommand - und StandardUICommand-Implementierung veranschaulicht, finden Sie im WinUI 2-Katalogbeispiel .
Siehe auch
Steuerelemente und Muster für Windows-Apps
Beispiele
Themenbeispiele
- UWP-Befehlsbeispiel (StandardUICommand)
- UWP-Befehlsbeispiel (XamlUICommand)
- UWP-Befehlsbeispiel (ICommand)
Weitere Beispiele
Windows developer