ApplicationContext

MessengerContext の派生クラスとして ApplicationContext クラスが定義されています。

このクラスの役割は純粋な MVVM Framework から逸脱しており、MVVM Framework 機能と OpenGLビューの機能とマウスオペレーションに関する機能の3つを統合する役割を担っています。(クラス構成 にあるクラス図を参照して下さい)

ApplicationContext は次の3つで特徴づけられます。

  • MessengerContext クラスを継承している
  • ISceneGraphContext インターフェイスを実装している
  • ICommandContext インターフェイスを実装している

MessengerContext については既に説明済みですので、残りの2つについて説明します。

ISceneGraphContext インターフェイス

このインターフェイスは MoNo.Wpf.dll の中に(C#で)次のように定義されています。

MoNo.Wpf.dll / ISceneGraphContext.cs
namespace MoNo.Wpf
{
  public interface ISceneGraphContext
  {
    /// <summary>
    /// このオブジェクトが DataContext としてバインドされている SceneGraph オブジェクトを取得します。
    /// </summary>
    /// <remarks>
    /// このプロパティは MoNo.RAIL フレームワーク側で設定されます。アプリケーション側で値を変更してはいけません。
    /// </remarks>
    SceneGraph SceneGraph { get; set; }
  }
}

コメントにも書かれているように、このインターフェイスをアプリケーション側で使用することはありません。

このインターフェイスは MoNo.RAIL の内部、正確には MoNo.Wpf.GLViewport コントロールの内部で使用されます。 DataContext プロパティが ISceneGraphContext を実装していると、GLViewport が保持しているシーングラフをそこに設定します。

つまり、ApplicationContext(の派生クラス)が GLViewport の DataContext にバインドされるように設定すれば、GLViewport に設定されたシーングラフが ApplicationContext にも設定される、ということです。

ICommandContext インターフェイス

このインターフェイスは MoNo.Framework.FSharp.dll の中に次のように定義されています。

MoNo.Framework.FSharp.dll / CommandContext.fs
type ICommandContext =
  inherit IContRunner
  abstract OperationDriver : Ctrl.OperationDriver
  abstract ViewContext : Graphics.IViewContext
  • IContRunner を継承していますので、継続モナドを実行する機能を持ちます。
  • OperationDriver を保持しており、マウスオペレーションに関する機能を持ちます。
  • ViewContext へのリンクを持っており、OpenGL ビューとつながっています。

このインターフェイスには次のような拡張メソッドが多数定義されています。 ICommandContext の重要性は上記の定義そのものよりも下記の拡張メソッドにあります。

MoNo.Framework.FSharp.dll / CommandContextExtension.fs
[<AutoOpen>]
module MoNo.Ctrl.CommandContextExtension
open System.Windows.Forms
open MoNo

type ICommandContext with
  member this.ByOperation (operation, getResult)  = ...
  member this.ByOperation operation               = ...
  member this.ByMouseOperation operation          = ...

  member this.GetMouseOperation (filter, button, ?action) =
    let operation = MouseOperation (this.ViewContext, filter, button)
    action |> Option.iter (fun action -> action operation)
    this.ByMouseOperation operation

  member this.GetMouseClick (button, ?action) = this.GetMouseOperation (MouseOperations.MouseClick, button, defaultArg action ignore)
  member this.GetMouseDown  (button, ?action) = this.GetMouseOperation (MouseOperations.MouseDown,  button, defaultArg action ignore)
  member this.GetMouseUp    (button, ?action) = this.GetMouseOperation (MouseOperations.MouseUp,    button, defaultArg action ignore)
  member this.GetMouseMove  (button, ?action) = this.GetMouseOperation (MouseOperations.MouseMove,  button, defaultArg action ignore)
  member this.GetMouseWheel   ?action = this.GetMouseOperation (MouseOperations.MouseWheel, MouseButtons.None, defaultArg action ignore)
  member this.GetLButtonClick ?action = this.GetMouseClick (MouseButtons.Left,   defaultArg action ignore)
  member this.GetRButtonClick ?action = this.GetMouseClick (MouseButtons.Right,  defaultArg action ignore)
  member this.GetMButtonClick ?action = this.GetMouseClick (MouseButtons.Middle, defaultArg action ignore)
  member this.GetLButtonDown  ?action = this.GetMouseDown  (MouseButtons.Left,   defaultArg action ignore)
  member this.GetRButtonDown  ?action = this.GetMouseDown  (MouseButtons.Right,  defaultArg action ignore)
  member this.GetMButtonDown  ?action = this.GetMouseDown  (MouseButtons.Middle, defaultArg action ignore)
  member this.GetLButtonUp    ?action = this.GetMouseUp    (MouseButtons.Left,   defaultArg action ignore)
  member this.GetRButtonUp    ?action = this.GetMouseUp    (MouseButtons.Right,  defaultArg action ignore)
  member this.GetMButtonUp    ?action = this.GetMouseUp    (MouseButtons.Middle, defaultArg action ignore)

これらの拡張メソッドはみな、Cont<'a> を返します。 つまり cont { ... } というコンピューテーション式の中で使えるということです。

特にマウスオペレーションに関するメソッドはすべて Cont<(IView * MouseEventArgs)> を返します。 従って次のようなコンピュテーション式でマウスクリックイベントを取得することができます。

cont {
  let! view, e = con.GetLButtonClick()
  ...
}