Komendy to jedna z nowości w WPFie. Oferują całkiem sporo:
- oddzielenie obiektu wywołującego od logiki przetwarzającej polecenie
- pozwalają na wywoływanie tej samej logiki w wielu miejscach programu (jak i zmianę jej w zależności od wymagań)
- sygnalizowanie użytkownikowi możliwość lub jej brak wykonania konkretnej komendy
Oczywiście jak wszystko istnieją także i ciemne strony komend, które być może w przyszłości zostaną naprawione:
- brak historii wywołanych komend
- brak możliwości cofnięcia komendy
- komendy nie mogą mieć wielu stanów
Po tym krótkim wstępie wad i zalet czas na sam model:
Command - reprezentuje zadanie (np. wytnij, wklej), nie zawiera żadnego kodu odpowiadającego za wykonanie zadania
Command Bindings - łączy polecenie z logiką
Command Sources - obiekt wywołujący polecenie (np. Button, MenuItem)
Command Targets - definiuje element w którym otrzymamy efekt działania polecenia.
Definiując kontrolkę, która ma korzystać poleceń definiujemy następujące właściwości:
Command - wskazuje jakie polecenie ma zostać wywołane (np. Cut, Paste)
CommandParameter - przekazuje dowolny parametr do komendy (nieobowiązkowo)
CommandTarget - wskazuje element w którym zostanie wykonane polecenie (nieobowiązkowo)
Bindując polecenia definiujemy trzy rzeczy:
- co ma się stać gdy zostanie wywołana komenda
- jak zdecydować kiedy jest możliwość wywołania komendy
- zasięg (jeden przycisk czy np. całe okno)
Zobaczmy na przykład:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.CommandBindings>
<CommandBinding Command="New" CanExecute="CommandBinding_CanExecute" Executed="CommandBinding_Executed" />
</Window.CommandBindings>
<Grid>
<Button Command="New" Content="New" Width="50" Height="25"/>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("New document");
}
}
}
Prosty przykład. Po kliknięciu użytkownik zobaczy MessageBox-a. Teraz dodamy menu i tam też metodę New:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.CommandBindings>
<CommandBinding Command="New" CanExecute="CommandBinding_CanExecute" Executed="CommandBinding_Executed" />
</Window.CommandBindings>
<Grid>
<Menu VerticalAlignment="Top">
<MenuItem Command="New" />
</Menu>
<Button Command="New" Content="New" Width="50" Height="25"/>
</Grid>
</Window>
Dodaliśmy 3 linijki kodu. Należy zauważyć, że nie nadaliśmy żadnego Headera elementowi menu. MenuItem jest na tyle sprytny, że pobierze sobie zawartość pola Text polecenia New. Wygodne i łatwe w użyciu.
Teraz zobaczymy przykład, w którym dzięki polecenią, program sam dokonuje oceny, czy dana komenda jest możliwa do wykonania czy też nie. Na początek kod:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<StackPanel Orientation="Vertical">
<Menu>
<MenuItem Command="Copy" />
<MenuItem Command="Cut" />
<MenuItem Command="Paste" />
</Menu>
<TextBox Name="txt" />
<StackPanel Orientation="Horizontal" Margin="0,20,0,0" >
<Button Margin="20" Content="Copy" Command="Cut" CommandTarget="{Binding ElementName=txt}" />
<Button Margin="20" Content="Paste" Command="Paste" CommandTarget="{Binding ElementName=txt}" />
</StackPanel>
</StackPanel>
</Window>
Po uruchomieniu zobaczymy:
Co należy zauważyć to to, że na starcie mamy coś w buforze schowka do wklejenia. Kolejnym aspektem jest aktywność klawisza Paste nawet po straceniu focusu z TextBoxa (w przypadku Menu klawisz Paste od razu traci aktywność). Dzieje się tak, gdyż w przypadku Buttona ustawiliśmy właściwość CommandTarget. Istotną rzeczą jest także, że możliwość Copy i Cut otrzymujemy dopiero po zaznaczeniu jakiegoś fragmentu tekstu w TextBoxie. Jak więc widać na starcie otrzymaliśmy niezły kawałek gotowej funkcjonalności.
Własne komendy
Oczywiście każdy programista chce mieć możliwość dodawania własnych poleceń. Nie jest to trudne. Zobaczmy na przykład implementacji:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
namespace WpfApplication2
{
public class DataCommands
{
private static RoutedUICommand requery;
static DataCommands()
{
InputGestureCollection inputs = new InputGestureCollection();
inputs.Add(new KeyGesture(Key.R, ModifierKeys.Control, "Ctrl+R"));
requery = new RoutedUICommand("Requery", "Requery", typeof(DataCommands), inputs);
}
public static RoutedUICommand Requery
{
get { return requery; }
}
}
}
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:WpfApplication2"
Title="MainWindow" Height="350" Width="525">
<Window.CommandBindings>
<CommandBinding Command="l:DataCommands.Requery" Executed="CommandBinding_Executed" />
</Window.CommandBindings>
<Grid>
<Button Name="button1" Command="l:DataCommands.Requery" Content="Click me!" />
</Grid>
</Window>
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("You create new command! Congratulations!");
}
Jak widać nic trudnego.
Brak komentarzy:
Prześlij komentarz