Příkazy jsou ve WPF velmi výhodné zvláště v případě, kdy potřebujete namapovat nějakou klávesovou zkratku pomocí KeyGesture(a k dispozici je i třída MouseGesture dědící taky od InputGesture, takže by šlo možná i nějak udělat gesto myší, nicméně s tímto jsem se ještě nikdy nesetkal, spíše bych řekl že to bude třeba klik na levé tlačítko myši + klaves na klávesnici) nebo pokud potřebujete automaticky povolovat / zakazovat nějaké tlačítko nebo cokoliv co lze namapovat na příkaz – stačí napsat metodu CanExecute třídy CommandBinding která pak se automaticky co cca 500ms volá a povoluje / zakazuje např. tlačítko.
Takže jak si udělat jednoduchý příkaz?
Prvním krokem je vytvoření třídy jakéhokoliv názvu(já vždy používám {nazev_programu}Commands. Do ní napište vytvoření instanci tříd RoutedCommand, která si za svůj první parametr bere název(který jsem zatím ale nikdy nepoužil), pak název libovolné třídy která je ve jmenném prostoru ve kterém budete tento příkaz využívat.
Toto byly 2 povinné parametry ale konstuktoru třídy jsou celkově 3. U mě fungoval i konstruktor bez parametrů a nebo konstruktor se 2mi zmiňovanými parametry + 3. který specifikuje zkratky vstupních zařízení(klávesnice, myš).
using HostingManager;
/// <summary>
/// Tato trida je pouze proto aby se v ni deklarovali Commands, ktere pak budes pouzivat v XAMLu
/// </summary>
using System.Windows.Input;
namespace HostingManager
{
public static class HostingManagerCommands
{
/// <summary>
/// Prikaz, na ktery se budeme odkazovat vzdy v vlastnosti Command
/// </summary>
public static RoutedCommand RunThread = new RoutedCommand();//"commandRunThread", typeof(MainWindow), new InputGestureCollection(new KeyGesture[] { new KeyGesture(Key.S, ModifierKeys.Control) }));
}
}
Pak si přidejte jmenný prostor nejlépe do root tagu ve vašem XAML souboru – v mém případě to je Window a jmenný prostor jsem si nazval src. Myslím že tento jmenný prostor byste tam už měli mít, takže si to prvně jen zkontrolujte
xmlns:src="clr-namespace:HostingManager"
Dalším krokem je vytvořit obalující element Window.CommandBindings hned za otevíracím tagem Window:
<Window.CommandBindings>
<CommandBinding Command="src:HostingManagerCommands.RunThread" x:Name="cmdRunThread" CanExecute="cmdRunThread_CanExecute" Executed="cmdRunThread_Executed"> </CommandBinding>
</Window.CommandBindings>
Pak je potřeba mít tlačítko které budeme automaticky povolovat nebo zakazovat a listbox, do něhož budeme počítat protože budeme používat vlákna:
<StackPanel Orientation="Vertical">
<Button x:Name="btnCancelUpload" Command="src:HostingManagerCommands.RunThread">
<Image Source="Run.png" Width="16" Height="16"> </Image>
</Button>
<ListBox x:Name="lbLog"> </ListBox>
</StackPanel>
Protože budeme používat vlákna, musíte si definovat třídu, která obsahuje delegáta odkazujícího na metodu která přidává do ListBox objekty:
using System.Windows.Controls;
public delegate void insertToListBoxWpf(ListBox lb, int index, object o);
public partial class IHWPF
{
public static insertToListBoxWpf delegateInsertToListBoxWpf = new insertToListBoxWpf(insertToListBoxWpfValue);
public static void insertToListBoxWpfValue(ListBox lb, int index, object o)
{
lb.Items.Insert(index, o);
}
}
Nakonec už jen napíšete do code-behind třídy Window metody CanExecute, Executed, OnLoad a také vytvoříme globální proměnnou Thread, abysme mohli toto vlákno zapínat i kontrolovat zda je živé – všechno v jiné metodě:
Thread thread = null;
public MainWindow()
{
this.Loaded += MainWindow_Loaded;
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
thread = new Thread(Run);
thread.Start();
}
void Run()
{
for (int i = 0; i < 5; i++)
{
Thread.Sleep(1000);
Dispatcher.Invoke(IHWPF.delegateInsertToListBoxWpf, lbLog, 0, i.ToString());
}
}
private void cmdRunThread_Executed(object sender, ExecutedRoutedEventArgs e)
{
Dispatcher.Invoke(IHWPF.delegateInsertToListBoxWpf, lbLog, 0, "Vlakno bylo znovu spusteno");
thread = new Thread(Run);
thread.Start();
}
/// <summary>
/// Az se vlakno dokonci, tato metoda znovu nastavi e.CanExecute na True
/// </summary>
/// <param name="sender">
/// <param name="e">
private void cmdRunThread_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
bool vr = true;
if (thread != null)
{
vr = !thread.IsAlive;
}
e.CanExecute = vr;
}
Výsledek? Tlačítko nešlo zmáčknout dokud vlákno běželo
