| ページ一覧 | ブログ | twitter |  書式 | 書式(表) |

MyMemoWiki

差分

ナビゲーションに移動 検索に移動
編集の要約なし
==[[WPF アクション]]==
[[WPF]] | [[.Net]] | [[Silverlight]] | [[Universal Windows Platform]] | [[C Sharp]] |
{{amazon|4798114200}}
*WPFにはアクションを扱うための共通の方法が3つある[[WPF]]にはアクションを扱うための共通の方法が3つある
**イベント、コマンド、およびトリガ
delegete { MessageBox.Show("Clicked!"); }
<blockquote>このコードはうまく機能するように見えるが、クリックされているのはボタンそのものではなく、ボタンの表示を構成する要素</blockquote>
*WPFではこれをシームレスに機能させるためにルーティングイベントという概念を導入[[WPF]]ではこれをシームレスに機能させるためにルーティングイベントという概念を導入
====ルーティングイベント====
*コンテンツとしてボタンを含むように変更する
===疎結合===
*Buttonのイベントを見ると、直接的なマウスイベント(MouseUp,MouseDownなど)とClickイベントの両方をサポートすることが分かる
*Clickはマウスイベントよりも上位に位置する抽象概念Clickはマウスイベントよりも上位に位置する抽象[[概念]](フォーカスがある状態でスペースキーや規定ボタンである場合Enterキー押下で発生する)
*Clickはセマンティック(意味的)イベントで、マウスイベントは、フィジカル(物理的)イベント
<blockquote>Clickイベントに対するコードを記述することは、特定の入力に縛られない、ボタンに縛られない(クリック可能なコンポーネントにのみ依存する)という利点がある</blockquote>
*ただし、イベント自体はメソッドの実装を特定のシグネチャにすることが要求される
=====Button.Clickのデリゲート=====
public delegate void RoutedEventHandler[[R]]outedEventHandler(object sender,RoutedEventArgs [[R]]outedEventArgs e);<blockquote>WPFの目標の一つは密接に結合されたフィジカルイベントから完全にセマンティックな通知までの幅広いアクションを許容すること[[WPF]]の目標の一つは密接に結合されたフィジカルイベントから完全にセマンティックな通知までの幅広いアクションを許容すること</blockquote>
====コマンド====
*疎結合を許容することでコントロールを劇的に変化させるテンプレートを記述することが可能となる
);
}
void CloseExecuted(object sender, ExecuteRouteEventArgs Execute[[R]]outeEventArgs e) {
this.Close();
}
*コマンドはWPFにおける最も疎結合なアクションモデルを表すコマンドは[[WPF]]における最も疎結合なアクションモデルを表す
*コマンドはアクションのソース(ボタンなど)とアクションのハンドラからの完全な抽象化を提供
<blockquote>アプリケーションを破壊せずに全く異なるコントロールを使用するようにスタイルの変更が可能となる</blockquote>
*コマンドと疎結合が導入されたことで、ソフトウェアが意図を宣言するモデルへと向かうことがわかる
**「このボタンがクリックされたら、Window.Close()を呼び出す」から「このコマンドが実行されたらウィンドウを閉じます」へと向かっている
*WPFの主要な基盤は宣言型プログラミングという考え方[[WPF]]の主要な基盤は宣言型プログラミングという考え方*視覚要素、UIレイアウトに加え、アプリケーションロジックの大半をマークアップで指定することが可能視覚要素、UIレイアウトに加え、アプリケーション[[ロジック]]の大半をマークアップで指定することが可能<blockquote>宣言型ロジックは、宣言形式の周囲で、ユーザーにツールを提供することによりエクスペリエンスを向上させたり、より高度なサービスをシステムで提供したりできるという点できわめて有効宣言型[[ロジック]]は、宣言形式の周囲で、ユーザーにツールを提供することによりエクスペリエンスを向上させたり、より高度なサービスをシステムで提供したりできるという点できわめて有効</blockquote>
=====アクションの処理方法によって、宣言型プログラミングのサポートレベルはことなる=====
{|class="wikitable"
|}
==イベント==
*イベントは他の[[.NETクラスライブラリと全く同じように機能NET]]クラスライブラリと全く同じように機能
*各オブジェクトは一覧のイベントを公開し、イベントに対しデリゲートを使用してリスナを添付できる
===ルーティングイベント===
*WPFはルーティングイベントに関連する追加の機能セットを備える[[WPF]]はルーティングイベントに関連する追加の機能セットを備える
{|class="wikitable"
!ルーティングイベント
|-
|直接イベント
|単一のソースで発生する単純なイベント。標準の[[.NETイベントとほぼ同じだが、WPFのルーティングイベントシステムに登録される点が異なるNET]]イベントとほぼ同じだが、WPFのルーティングイベントシステムに登録される点が異なる
|-
|バブルイベント
|-
|}
*バブルイベントとトンネルイベントは裏表の関係、通常、対になっており、トンネルバージョンには、Previewという接頭語がつくバブルイベントとトンネルイベントは裏表の関係、通常、対になっており、トンネルバージョンには、Pre[[vi]]ewという接頭語がつく
====要素の階層を作成してイベントをリッスンする====
*グループボックスと複数のボタンを含むウィンドウ
<Window ...
PreviewMouseRightbuttonDownPre[[vi]]ewMouseRightbuttonDown="WindowPreviewRightButtonDownWindowPre[[vi]]ewRightButtonDown" MouseRightButtonDownMouse[[R]]ightButtonDown="WindowRightButtonDownWindow[[R]]ightButtonDown"
>
<GroupBox
PreviewMouseRightbuttonDownPre[[vi]]ewMouseRightbuttonDown="GroupBoxPreviewRightButtonDownGroupBoxPre[[vi]]ewRightButtonDown" MouseRightButtonDownMouse[[R]]ightButtonDown="GroupBoxRightButtonDownGroupBox[[R]]ightButtonDown"
>
<StackPanel>
<Button>ボタン1</Button>
<Button
PreviewMouseRightbuttonDownPre[[vi]]ewMouseRightbuttonDown="ButtonTwoPreviewRightButtonDownButtonTwoPre[[vi]]ewRightButtonDown" MouseRightButtonDownMouse[[R]]ightButtonDown="ButtonTwoRightButtonDownButtonTwo[[R]]ightButtonDown"
>
ボタン2
</Window>
*イベントハンドラでイベント名を出力
void ButtonTwoPreviewRightButtonDownButtonTwoPre[[vi]]ewRightButtonDown(object sender,MouseButtonEventArgs e) { Debug.WriteLine("ButtonTwo PreviewRightButtonDownPre[[vi]]ewRightButtonDown");
}
void ButtonTwoRightButtonDownButtonTwo[[R]]ightButtonDown(object sender,MouseButtonEventArgs e) { Debug.WriteLine("ButtonTwo RightButtonDown[[R]]ightButtonDown");
}
void GroupBoxPreviewRightButtonDownGroupBoxPre[[vi]]ewRightButtonDown(object sender,MouseButtonEventArgs e) { Debug.WriteLine("GroupBox PreviewRightButtonDownPre[[vi]]ewRightButtonDown");
}
void GroupBoxRightButtonDownGroupBox[[R]]ightButtonDown(object sender,MouseButtonEventArgs e) { Debug.WriteLine("GroupBox RightButtonDown[[R]]ightButtonDown");
}
void WindowPreviewRightButtonDownWindowPre[[vi]]ewRightButtonDown(object sender,MouseButtonEventArgs e) { Debug.WriteLine("Window PreviewRightButtonDownPre[[vi]]ewRightButtonDown");
}
void WindowRightButtonDownWindow[[R]]ightButtonDown(object sender,MouseButtonEventArgs e) { Debug.WriteLine("Window RightButtonDown[[R]]ightButtonDown");
}
=====イベント順序=====
#Window PreviewMouseRightButtonDownPre[[vi]]ewMouseRightButtonDown#GroupBox PreviewMouseRightButtonDownPre[[vi]]ewMouseRightButtonDown#ButtonTwo PreviewMouseRightButtonDownPre[[vi]]ewMouseRightButtonDown#ButtonTwo MouseRightButtonDownMouse[[R]]ightButtonDown#GroupBox MouseRightButtonDownMouse[[R]]ightButtonDown#Window MouseRightButtonDownMouse[[R]]ightButtonDown
*コントロールの既定の動作は常にイベントのバブルバージョンで実装する必要がある
*プレビューイベントを使用しないパターンにより、開発者がプレビューイベントを使用してロジックにフックしたり、既定の動作をキャンセルすることが可能になるプレビューイベントを使用しないパターンにより、開発者がプレビューイベントを使用して[[ロジック]]にフックしたり、既定の動作をキャンセルすることが可能になる
*イベントルーティングの任意のポイントでHandledプロパティを設定し、さらなるイベントハンドラが呼び出されるのを防ぐことができる
*すべての要素がクリックされるのを防ぐ
public Window() {
this.PreviewMouseRightButtonDown Pre[[vi]]ewMouseRightButtonDown += WindowPreviewRightButtonDownWindowPre[[vi]]ewRightButtonDown;
}
void WindowPreviewRightButtonDownWindowPre[[vi]]ewRightButtonDown(object sender, MouseButtonEventArgs e) {
e.Handled = true;
}
*Handleプロパティはすべてのルーティングイベントが共有するプロパティの一つ
public class RoutedEventArgs [[R]]outedEventArgs : EventArgs {
public bool Handled { get; set; }
public object OriginalSource { get; }
public RouteEvent RouteEvent [[R]]outeEvent [[R]]outeEvent { get; set; }
public object Source { get; set; }
}
<blockquote>WPFはルーティングという概念をイベントに含めるように[[.NETイベントモデルを拡張し、それにより要素の合成を可能にする。ほかのアクション処理機構は、すべてこの基盤イベントルーティングモデル状に構築されるNET]]イベントモデルを拡張し、それにより要素の合成を可能にする。ほかのアクション処理機構は、すべてこの基盤イベントルーティングモデル状に構築される</blockquote>
==コマンド==
*WPFのほとんどのイベントは、各コントロールの実装の詳細に結びついている[[WPF]]のほとんどのイベントは、各コントロールの実装の詳細に結びついている
*イベントはコードの特定の部分をコントロールからの通知に結び付ける場合には便利だが、もっと抽象的に処理を行いたい場合もある
===プログラムを終了する機能===
====イベントでの実装例====
*まず必要なのは、プログラムを終了するためのメニュー
<MenuItem [[Menu]]Item Hader="ファイル(_F)"> <MenuItem [[Header]]="終了(_X)" Click="ExitClicked"/> </MenuItem[[Menu]]Item>
*次に分離コードでイベントハンドラを実装
void ExitClicked(object sender, RouteEventArgs [[R]]outeEventArgs e) {
Application.Current.Shutdown();
}
*この方法はうまく機能するが、アプリケーションを終了するハイパーリンクも加えてみるこの方法はうまく機能するが、アプリケーションを終了するハイパー[[リンク]]も加えてみる
<TextBlock>
<Hyperlink Click="ExitClicked">終了</Hyperlink>
}
*CanExecute はコマンドが利用可能かどうか
**使用可能の概念を共有することで同じコマンドに結び付けられている複数のコントロールが一貫した共有可能状態を持つことが可能となる使用可能の[[概念]]を共有することで同じコマンドに結び付けられている複数のコントロールが一貫した共有可能状態を持つことが可能となる
*Execute コマンドの実行をトリガする
====対応するコマンドの実装====
protected virtual [[vi]]rtual void OnClick(RoutedEventArgs e) {
if (Command != null && Command.CanExecute(CommandParameter)) {
Command.Execute(CommandParmeter);
}
====マークアップとバインド====
<MenuItem [[Menu]]Item Hader="ファイル(_F)"> <MenuItem [[Header]]="終了(_X)"> <MenuItem[[Menu]]Item.Command>
<l:Exit />
</MenuItem[[Menu]]Item.Command> </MenuItem[[Menu]]Item> </MenuItem[[Menu]]Item>
:
<TextBlock>
*ICommand をフィールド型とすることで、Exitの実装を完全にプライベートにできる利点
*これでExitをプライベートクラスとしてマークし、静的フィールドにバインドするようにマークアップを変更できる
<MenuItem [[Menu]]Item Hader="ファイル(_F)"> <MenuItem [[Header]]="終了(_X)"
Command="{x:Static l:Window1.ExitCommand}">
</MenuItem[[Menu]]Item>
<blockquote>こうすることで、ウィンドウでコマンドを公開することで、機能セットを発行できる。</blockquote>
====変更====
*コマンドで新しいイベントを定義し、イベントルーティングシステムを利用してコンポーネントに通知することができる
class Exit : ICommand {
public static readonly RouteEvent [[R]]outeEvent ExecuteEvent = EventManager.RegisterRouteEvent[[R]]egister[[R]]outeEvent(
"Execute",
RoutingStrategy[[R]]outingStrategy.Bubble, typeof(RoutedEventHandler[[R]]outedEventHandler),
typeof(Exit)
);
*現在の要素を検索するようにExecuteを変更し、適切なイベントを発行する
public void Execute(object parameter) {
RoutedEventArgs [[R]]outedEventArgs e = new RoutedEventArgs[[R]]outedEventArgs(Exit.ExecuteEvent, Keyboard.FocusedElement); Keyboard.FocusedElement.RaiseEvent[[R]]aiseEvent(e);
}
<blockquote>ここからコマンドバインディングという概念が生まれるここからコマンドバインディングという[[概念]]が生まれる</blockquote>
====コマンドバインディング====
*コマンドバインディングとは、コマンドの実装を、そのコマンドの身元から切り離す機能
AddHandler(Exit.ExecuteEvent, ExitExecuted);
}
void ExitExecuted(object sender, RoutedEventArgs [[R]]outedEventArgs e) {
this.Close();
}
<blockquote>このケースでは、Exitコマンドは要素ツリーでExecuteイベントを発生させ、Windowがそのイベントをリッスンして対応できるようにする</blockquote>
#メニュー項目がクリックされる
#MenuItemがコマンドでExecuteを呼び出す[[Menu]]ItemがコマンドでExecuteを呼び出す#Exitの実装がフォーカスが設定されているオブジェクト(この場合MenuItemこの場合[[Menu]]Item)で、Exit.Executeイベントを発生させる
#そのイベントが要素ツリーをバブルアップ
#ウィンドウがExit.Execute(ウィンドウを閉じる)を実行する
====RoutedCommand[[R]]outedCommand====*この方法で、入力バインディング、パラメータ、およびその他の機能をサポートするように基盤のICommandモデルを拡張することも可能この方法で、入力バインディング、パラメータ、および[[その他]]の機能をサポートするように基盤のICommandモデルを拡張することも可能<blockquote>ただしフレームワークには、これらのほとんどを処理する組み込みのユーティリティクラス、RoutedCommand ただしフレームワークには、これらのほとんどを処理する組み込みのユーティリティクラス、[[R]]outedCommand がすでに含まれている</blockquote>
*ルーティングコマンドは、コマンドの実装をコマンドの身元から完全に分離する
*コマンドの定義は静的つまり、コマンドの定義は、コマンドの身元を提供する一種のトークンに過ぎない
public partial class Window1 : Window {
public static readonly ICommand ExitCommand =
new RoutedCommand[[R]]outedCommand("Exit", typeof(Window1));
:
}
CommandBindings.Add(new CommandBinding(ExitCommand, ExitExecuted));
}
void ExitExecuted(object sender, ExecutedRoutedEventArgs Executed[[R]]outedEventArgs e) {
this.Close();
}
*コマンドバインディングを使用すると、コマンドを使用可能にするか否かを判断するためのロジックを使用できるコマンドバインディングを使用すると、コマンドを使用可能にするか否かを判断するための[[ロジック]]を使用できる
====InputBindingsプロパティ====
*InputBindingsプロパティを使用して入力ジェスチャをマップできる
====セキュアコマンド====
*切り取り、コピー、貼り付けなどの一部コマンドはセキュリティに影響を与える
*システムがこれらの操作をユーザーによって要求された場合のみに実行することを保証するために、RoutedCommandは、ユーザーによって開始されたかどうかを追跡可能システムがこれらの操作をユーザーによって要求された場合のみに実行することを保証するために、[[R]]outedCommandは、ユーザーによって開始されたかどうかを追跡可能
<blockquote>一般にアプリケーションロジックはイベントハンドラではなく、コマンドの観点で実装することが推奨される。イベントハンドラが必要なケースの多くはトリガーを使用したほうがうまく処理できる。一般にアプリケーション[[ロジック]]はイベントハンドラではなく、コマンドの観点で実装することが推奨される。イベントハンドラが必要なケースの多くはトリガーを使用したほうがうまく処理できる。</blockquote>
===コマンドとデータバインディング===
*コマンドを使用する場合のもっとも強力な機能はデータバインディングの統合
*CommandとCommandParameterはいずれも要素のプロパティのため、データをバインドすることができる
*コマンドを使用することでデータ駆動型のロジックも可能となるコマンドを使用することでデータ駆動型の[[ロジック]]も可能となる
====ドライブ内のファイルをリストするアプリケーション例====
<Window x:Class="..."

案内メニュー