私はいくつかの WPF プログラミングを行ってきましたが、得られなかったものの 1 つはコマンド パターンでした。すべての例は、組み込みのもの、編集、切り取り、貼り付けのようです。カスタム コマンドのベスト プラクティスの例や提案はありますか?
4 に答える
あはは!私が答えられる質問!まず、個人的には、XAML ではなくコードでコマンドを定義してフックする方が簡単であることに言及しておく必要があります。これにより、すべての XAML アプローチよりも柔軟にコマンドのハンドラーを接続できます。
必要なコマンドと、それらが何に関連しているかを理解する必要があります。私のアプリケーションでは、現在、次のような重要なアプリケーション コマンドを定義するためのクラスがあります。
public static class CommandBank
{
/// Command definition for Closing a window
public static RoutedUICommand CloseWindow { get; private set; }
/// Static private constructor, sets up all application wide commands.
static CommandBank()
{
CloseWindow = new RoutedUICommand();
CloseWindow.InputGestures.Add(new KeyGesture(Key.F4, ModifierKeys.Alt));
// ...
}
ここで、コードをすべてまとめておきたかったので、コマンドに対してコードのみのアプローチを使用すると、上記のクラスに次のメソッドを配置できます。
/// Closes the window provided as a parameter
public static void CloseWindowExecute(object sender, ExecutedRoutedEventArgs e)
{
((Window)e.Parameter).Close();
}
/// Allows a Command to execute if the CommandParameter is not a null value
public static void CanExecuteIfParameterIsNotNull(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = e.Parameter != null;
e.Handled = true;
}
そこにある 2 番目の方法は、他のコマンドと共有することもでき、あちこちで繰り返す必要はありません。
このようにコマンドを定義したら、それらを任意の UI に追加できます。以下では、Window がロードされたら、Window と MenuItem の両方にコマンド バインディングを追加してから、ループを使用して入力バインディングを Window に追加し、すべてのコマンド バインディングに対してこれを行います。渡されるパラメーターは Window 自体であるため、上記のコードはどの Window を試行して閉じるかを認識しています。
public partial class SimpleWindow : Window
{
private void WindowLoaded(object sender, RoutedEventArgs e)
{
// ...
this.CommandBindings.Add(
new CommandBinding(
CommandBank.CloseWindow,
CommandBank.CloseWindowExecute,
CommandBank.CanExecuteIfParameterIsNotNull));
foreach (CommandBinding binding in this.CommandBindings)
{
RoutedCommand command = (RoutedCommand)binding.Command;
if (command.InputGestures.Count > 0)
{
foreach (InputGesture gesture in command.InputGestures)
{
var iBind = new InputBinding(command, gesture);
iBind.CommandParameter = this;
this.InputBindings.Add(iBind);
}
}
}
// menuItemExit is defined in XAML
menuItemExit.Command = CommandBank.CloseWindow;
menuItemExit.CommandParameter = this;
// ...
}
// ....
}
その後、後で WindowClosing および WindowClosed イベントのイベント ハンドラーも作成します。実際のコマンドの実装は、できるだけ小さく汎用的にすることをお勧めします。この場合のように、保存されていないデータがある場合に Window のクローズを停止しようとするコードを配置しようとはせず、そのコードを WindowClosing イベント内にしっかりと保持しました。
ご不明な点がございましたら、お気軽にお問い合わせください。:)
ここに貼り付けます:
WPF の重要な新しい概念に関する Adam Nathan のサンプルの章: コマンド
Keyvan Nayyeri: カスタム WPF コントロールにコマンドを追加する方法
Ian Griffiths: Avalon の入力、コマンド、およびハンドラー
MSDN ライブラリ: CommandBinding クラス
MSDN ライブラリ: EditingCommands クラス
MSDN ライブラリ: ApplicationCommands クラス
MSDN ライブラリ: NavigationCommands クラス
MSDN ライブラリ: ComponentCommands クラス
WPF SDK サンプルにも埋もれていますが、私が拡張した RichTextBox 編集に関する素晴らしいサンプルがあります。ここで見つけることができます: RichTextEditor.zip
MSDN マガジンの 2008 年 9 月版では、Brian Noyes が RoutedCommand/RoutedEvents に関する優れた記事を掲載しています!!!
リンクは次のとおりです 。 http://msdn.microsoft.com/en-us/magazine/cc785480.aspx
XAML に関することは、「単純な」プログラムには問題ないということですが、悲しいことに、共有機能などを実行したい場合にはうまく機能しません。いくつかのクラスと UI があり、そのすべてに無効にされていないコマンドがあるとします。ウィンドウまたはユーザー コントロールごとに「CanAlwaysExecute」メソッドを記述する必要があります。それはあまりDRYではありません。
いくつかのブログを読み、いくつかのことを試した結果、見た目、スタイル、アニメーション、およびトリガーだけを考慮して XAML を作成することにしました。イベント ハンドラーとコマンドの接続はすべて、コード ビハインドで行われます。:)
ところで、もう 1 つの落とし穴は Input バインディングです。それらをキャッチするには、Input バインディングを含むオブジェクトにフォーカスを合わせる必要があります。たとえば、いつでも使用できるショートカット (F1 キーでヘルプを開くなど) を使用するには、その入力バインドを Window オブジェクトに設定する必要があります。これは、アプリがアクティブなときに常にフォーカスがあるためです。コード メソッドを使用すると、親ウィンドウに入力バインディングを追加する可能性がある UserControls の使用を開始する場合でも、それが容易になります。