This article has been localized into Persian by the community.
استفاده از فرمان ها در WPF
در قسمت قبلی، در مورد تئوری فرمان ها و اینکه آنها چطور کار میکنند، بحث کردیم. در این قسمت، در باره نحوه بکارگیری فرمان ها، از طریق واسط کاربری (صفحه نمایش) و ساخت انقیاد فرمان (command bindings) که برنامه را به صفحه نمایش وصل می کند، بحث خواهیم کرد.
ما با مثالی بسیار ساده شروع می کنیم:
<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");
}
}
}
ما یک انقیاد(اتصال) فرمان (command binding) در یک پنجره را، از طریق اضافه کردن CommandBindings collection انجام میدهیم. ما مشخص می کنیم که کدامیک از فرمان ها را میخواهیم استفاده کنیم (فرمان جدید از فرمان های کاربردی (ApplicationCommands))، بهمراه دو Event Handler. صفحه کاربری که بالا نمایش داده شده است، شامل یک دلکمه است که از طریق فرمان به برنامه متصل شده است و ما از خصوصیت Command نیز (برای Bold کردن نوشته) استفاده کردیم.
در Code-behind (جایی که بخش کد نویسی متصل به صفحه نمایش است)، دو رویداد را مدیریت (handle) میکنیم. مدیریت CanExecute، که هنگامی که نرم افزار کار خاصی انجام نمی دهد، WPF آنرا صدا می کند تا چک کند که آیا فرمانی در حال حاضر موجود هست یا نه، مثال ساده ای است و ما انتظار داریم که این فرمان خاص همیشه در دسترس باشد. این کار از طریق true کردن یکی از آرگیومنت های رویداد خصوصیت CanExecute قابل انجام است.
هندلر (handler) تگ Executed به سادگی یک پیغام را هنگامی که فرمان صدا زده می شود فرا میخواند. اگر شما مثال رو اجرا کنید و دکمه را فشار دهید، این پیغام را خواهید دید. موضوعی که می توانید به آن توجه کنید این است که این فرمان دارای کلمات میانبر می باشد که همراه با کدی که نوشته اید بصورت پیش فرض قابل استفاده است. بجای فشار دادن دکمه، شما می توانید از کلمات میانبر Ctrl+N استفاده کنید. این کار همان کار فشار دادن دکمه را انجام میدهد.
نحوه استفاده از تابع می توانی اجرا کنی؟ (CanExecute)
در مثال اول، رویداد CanExecute را که true بر میگرداند را اجرا کردیم. بنابراین دکمه همیشه در دسترسمان خواهد بود. اگرچه، به طور مسلم این مثال برای همه دکمه ها صدق نخواهد کرد. در بسیاری از موارد،بسته به شرایط نرم افزار شما، شما میخواهید یک دکمه فعال یا غیر فعال شود.
یک مثال شایع این هست که شما میخواهید دکمه های کپی و بریدن (Cut) زمانی کار کند که یک متنی انتخاب شده باشد و همچنین Paste کار کند هنگامی که متنی در کلیپ برد(Clipboard) کپی شده باشد. این دقیقا کاری است که ما در مثال زیر انجام میدهیم:
<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();
}
}
}
برای شروع، یک صفحه نمایش بسیار ساده با دو تا دکمه و یک TextBlock داریم. دکمه اول کار کپی کردن در کلیپ برد (Clipboard) را برعهده دارد و دومی کار چسباندن (Paste).
در Code-Behind، دو رویداد برای هر دکمه داریم: یکی اقدام مشخصی را انجام میدهد، که نامش _Executed است و دیگری رویداد CanExecute. برای هر کدام از آنها شما میتوانید ببینید که منطقی را لحاظ کردم تا مشخص شود آیا آن اقدام می تواند انجام شود یا خیر. سپس از طریق بکارگیری تگ CanExecute مقدار را به EventArgs بر می گرداند.
چیز بسیار جالب در این ارتباط این است که شما نیازی به فراخوانی این توابع برای بروز رسانی دکمه ها ندارید. WPF به صورت خودکار هنگامی که CPU لحظه ای بیکار میشود، این بروز رسانی را برای شما انجام میدهد و اطمینان خاطر پیدا میکند که رابط کاربری شما همیشه بروز است.
پیش فرض رفتار فرمان و هدف فرمان
هماهنطور که در مثال قبلی دیدیم، مدیریت مجموعه ای از فرمان ها نیازمند نوشتن کد می باشد، همچنین نیازمند معرفی تعداد زیادی از توابع و منطق استاندارد است. احتمالا به خاطر همین موضوع تیم WPF تصمیم گرفته که برخی از این توابع رو بصورت پیش فرض و آماده در اختیار کاربران قرار دهد. در واقع، ما میتوانستیم از نوشتن آن همه کد در مثال قبلی در Code-Behind خودداری کنیم، چراکه کنترل TextBox در WPF بصورت خودکار فرمان هایی نظیر کپی کردن، بریدن، چسباندن، Undo و Redo کردن را مدیریت میکند.
WPF این کار را از طریق مدیریت کردن رویدادهای CanExecute و Executed ، وقتی که کنترلی مثل TexBlock از تگ focus استفاده کرده است، انجام میدهد. شما میتوانید رویدادهای بالا را همانطور که ما انجام دادیم، خودتان باز تولید کنید (Override). اما اگر شما همان رفتار متعارف و معمولی را انتظار دارید میتوانید از تابع پیشفرضی که WPF در اختیار شما میگذارد استفاده کنید. فقط نگاه کنید چه قدر می تواند استفاده از این توابع از پیش تعریف شده آسان باشد:
<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>
به هیچ کدی برای اجرای مثال بالا در Code-Behind احتیاج نیست. WPF همه فرآیند انجام کار رو بصورت خودکار، خودش برای ما انجام میدهد. اما چون ما میخواهیم از این فرمان های خاص در یک کنترل خاص استفاده کنیم، TextBox تمام کار را برای ما خواهد کرد.
توجه کنید که چطور از تگ CommandTarget در دکمه ها استفاده کردم تا اتصال (Bind) فرمان ها را با کنترل TextBox فراهم کنم. این کار یکی از ضروریات می باشد، چراکه WrapPanel بصورت متفاوتی focus را مدیریت میکند. به طور مثال یک نوار ابزار یا منو این کار را بصورت قبل انجام میدهد ولی باوجود این منطقی به نظر میرسد که برای آن فرمان ها هدف را مشخص کنیم.
خلاصه
استفاده کردن از فرمان ها بسیار مشخص و ساده است، ولی نیازمند اضافه کردن چند تگ و کد است. البته استفاده کردن از چنین ساختاری مزیت ها بارزی دارد، چراکه میتوانید یک اقدام (action) را در چندین مکان فراخوانی کنید، و یا اینکه فرامینی که توسط تیم WPF در اختیار کاربر قرار میگیرد را همانطور که در مثال دیدیم، به سادگی بکاربگیرید.