This article has been localized into Swedish by the community.
Använda WPF-kommandon
I förra avsnittet diskuterade vi en hel del teori om vad kommandon är och hur de fungerar. I detta kapitel skall vi studera hur vi praktiskt kan använda kommandon genom att applicera dem på användargränssnittselement och skapa bindningar som länkar ihop det hela.
Vi börjar med ett mycket enkelt exempel:
<Window x:Class="WpfTutorialSamples.Commands.UsingCommandsSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="UsingCommandsSample" Height="100" Width="200">
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.New" Executed="NewCommand_Executed" CanExecute="NewCommand_CanExecute" />
</Window.CommandBindings>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Command="ApplicationCommands.New">New</Button>
</StackPanel>
</Window>
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
namespace WpfTutorialSamples.Commands
{
public partial class UsingCommandsSample : Window
{
public UsingCommandsSample()
{
InitializeComponent();
}
private void NewCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
private void NewCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("The New command was invoked");
}
}
}
Vi definierar en kommandobindning för fönstret genom att lägga till den i fönstrets ”CommandBindings”-kollektion. Vi specificerar att kommandot som vi vill använda ( ”New”- kommandot från ”ApplicationCommands”) samt två eventhanterare. Användargränssnittet innehåller endast en knapp som vi förbinder med kommandot genom att använda egenskapen Command.
I den bakomliggande koden hanterar vi två event. Hanteraren CanExecute, som WPF anropar när applikationen är inaktiv för att se om det specifika kommandot är tillgängligt för tillfället, är mycket enkel i detta exempel eftersom vi vill att detta speciella kommando alltid skall vara tillgängligt. Detta åstadkomms genom att sätta egenskapen CanExecute till ”true”;
Hanteraren Executed visar en meddelandebox när kommandot åberopas. Om du kör programmet och klickar på knappen kommer du att få ett meddelande i meddelandeboxen. Notera att kommandot har en standard tangentbordskombination definierad som du får som extra bonus. Istället för att klicka på knappen kan du använda kombinationen Ctrl+N på tangentbordet – resultatet blir detsamma.
Använda metoden CanExecute
I det första exemplet iplementerade vi en ”CanExecute”-event som helt enkelt returnerade värdet ”true”, knappen blev på så sätt alltid tillgänglig. Detta är förstås inte önskvärt för alla knappar – i många fall vill du att knappen skall aktiveras eller deaktiveras beroende på något tillstånd i din applikation.
Ett vanligt fall är knappar som används för ”Windows clipboard” ochr du vill att ”Cut”- och ”Copy”-knapparna bara ska vara tillgängliga när det finns markerad text och ”Paste”-knapparna bara skall vara tillgänglig när det finns text i ”Clipboard”. Det är precis detta som vi vill åstadkomma i detta exempel:
<Window x:Class="WpfTutorialSamples.Commands.CommandCanExecuteSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CommandCanExecuteSample" Height="200" Width="250">
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Cut" CanExecute="CutCommand_CanExecute" Executed="CutCommand_Executed" />
<CommandBinding Command="ApplicationCommands.Paste" CanExecute="PasteCommand_CanExecute" Executed="PasteCommand_Executed" />
</Window.CommandBindings>
<DockPanel>
<WrapPanel DockPanel.Dock="Top" Margin="3">
<Button Command="ApplicationCommands.Cut" Width="60">_Cut</Button>
<Button Command="ApplicationCommands.Paste" Width="60" Margin="3,0">_Paste</Button>
</WrapPanel>
<TextBox AcceptsReturn="True" Name="txtEditor" />
</DockPanel>
</Window>
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
namespace WpfTutorialSamples.Commands
{
public partial class CommandCanExecuteSample : Window
{
public CommandCanExecuteSample()
{
InitializeComponent();
}
private void CutCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = (txtEditor != null) && (txtEditor.SelectionLength > 0);
}
private void CutCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
txtEditor.Cut();
}
private void PasteCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = Clipboard.ContainsText();
}
private void PasteCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
txtEditor.Paste();
}
}
}
Vi har här ett mycket enkelt användargränssnitt med två knappar och en textruta. Den första knappen skall klippa ut text och spara det på ”Clipboard” och den andra skall klistra in text från denna.
I den bakomliggande koden har vi två event för via knapp: en som utför den aktuella uppgiften, namnet slutar med ”_Executed”, och en med en som konrollerar om uppgiften är genomförbar, och där namnet slutar på _CanExecute. För den senare åsätts ett värde på CanExecute via ”Event Args”.
Det coola med detta är att du behöver inte anropa dessa metoder för att uppdatera knapparna – WPF gör detta automatiskt så snart applikationen har ledig kapacitet för att säkerställa att gränssnittet alltid förblir uppdaterat.
Standard kommandouppförande och ”CommandTarget”
Som vi såg i exemplet kan hanteringen av några kommandon ge upphov till rätt mycket kod, mycket bestående av metoddeklarationer och standardlogik. Det är antagligen därför som WPF-teamet beslöt sig för att bespara dig lite av kodningsjobbet. Faktum är att vi kunde ha klarat oss helt utan all bakomliggande kod i exemplet eftersom ”WPF TextBox” automatiskt kan hantera vanliga kommandon som ”Copy”, ”Paste”, ”Undo” och ”Redo”.
WPF sköter själv hanteringen eventen ”Executed” och ”CanExecute” när text-kontroll som ”TextBox” är i fokus. Du kan ersätta, ”override”, dessa event, vilket vi faktiskt gjorde i exemplet, men om man bara är intresserad av normal funktion kan man låta WPF förbinda kommandon och textruta och förlita sig på automatgenererad kod. Se nedan hur mycket enklare det blir:
<Window x:Class="WpfTutorialSamples.Commands.CommandsWithCommandTargetSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CommandsWithCommandTargetSample" Height="200" Width="250">
<DockPanel>
<WrapPanel DockPanel.Dock="Top" Margin="3">
<Button Command="ApplicationCommands.Cut" CommandTarget="{Binding ElementName=txtEditor}" Width="60">_Cut</Button>
<Button Command="ApplicationCommands.Paste" CommandTarget="{Binding ElementName=txtEditor}" Width="60" Margin="3,0">_Paste</Button>
</WrapPanel>
<TextBox AcceptsReturn="True" Name="txtEditor" />
</DockPanel>
</Window>
Ingen bakomliggande kod behövs för detta exempel – WPF sköter allt åt oss så länge vi nöjer oss med standarduppsättningen av kommandon. Textrutan gör jobbet själv.
Notera att vi använder egenskapen CommandTarget för knapparna för att binda kommandona till textrutan. Detta är nödvändigt i detta speciella exempel därför att ”WrapPanel” hanterar inte fokus på samma sätt som t.ex. ”Toolbar” eller ”Menu”, men det verkar också vettigt att associera ett kommando med ett mål.
Sammanfattning
Att använda kommandon är inget konstigt i sig, men det innebär lite extra ”markup” och kod. Men belöningen kan bli speciellt tydlig när man åberopar samma åtgärd från flera ställen eller då man använder inbyggda kommandon som WPF kan hantera på egen hand som vi såg i det sista exemplet.