Smart.Windows.Mvc補足(2)

Smart.Windows.Mvcの、画面遷移以外の項目についてで(・ω・)

同じ画面に複数のID

アプリケーションでは、ある項目に対する新規作成画面と編集画面のように、入力値やヴァリデーションが多少異なるだけで、その他の処理はほぼ一緒な画面というものがよくあります。
Smart.Windows.Mvcでは、画面IDのobjectに対して画面のTypeをDictionary管理しているので、同じ画面クラスに対して複数のIDを割り当てることにより、1つのクラスで複数画面を扱えます。
ViewAttributeを使用して画面登録を行う場合、下記のように複数のViewAttributeを定義すればOKです(・∀・)

[View(Views.DataDetailNew)]
[View(Views.DataDetailEdit)]
public partial class DataDetailView : AppViewBase
{
...
}

また、その画面がどの画面IDを指定されて遷移してきたかを切り分けるには、ViewForwardEventArgsのViewIdプロパティを使用します。

public override void OnViewOpen(ViewForwardEventArgs args)
{
    // 表示
    if( (Views)args.ViewId == Views.DataDetailEdit )
    {
        // Edit
    }
    else
    {
        // New
    }
}

スタック型遷移

Controller.Forward()による画面遷移では、前画面を破棄して次画面をオープンします。しかし、画面間を親子的に扱いたい場合等のように、前画面のインスタンスを保持したまま次画面へ遷移し、その後前画面のインスタンスへ戻ってきたいようなケースが存在します。
その場合には、Controller.Push()、Controller.Pop()を使用して画面をスタックしながら遷移を行います(・∀・)

[View(Views.Stack1)]
public partial class Stack1View : AppViewBase
{
...
    private void PushButton_Click(object sender, EventArgs e)
    {
        // Stack1Viewのインスタンスを保持しながら次画面へ遷移
        Controller.Push( Views.Stack2 );
    }
}
[View(Views.Stack2)]
public partial class Stack2View : AppViewBase
{
...
    private void PopButton_Click(object sender, EventArgs e)
    {
        // スタックにつまれた前画面へ遷移
        Controller.Pop();
    }
}

また、Controller.Pop()では引数にPopする画面のスタック数を指定することが可能です。

[View(Views.Stack3)]
public partial class Stack3View : AppViewBase
{
...
    private void Pop2Button_Click(object sender, EventArgs e)
    {
        // スタックにつまれた2つ前の画面へ遷移
        Controller.Pop( 2 );
    }
}

なお、画面の初回表示時とController.Pop()により戻ってきた時で処理を切り分けたい場合があると思いますが、その場合にはViewForwardEventArgsのIsPopBackプロパティを使用します。

public override void OnViewOpen(ViewForwardEventArgs args)
{
    if( args.IsPopBack )
    {
        // Popによる画面遷移
    }
}

画面遷移/終了イベント

Controllerには、画面遷移毎に呼び出されるForwardingイベント、コントローラ終了時に呼び出されるExitedイベントが存在します。

public partial class MainForm : Form
{
    private readonly Controller controller;

    public MainForm()
    {
        InitializeComponent();

        // コントローラー初期化
        controller = new Controller( new ControlViewProvider( ViewPanel)  );
        controller.Forwarding += OnForwarding;
        controller.Exited += OnExited;
...
    }

    private void OnForwarding(object sender, ViewForwardEventArgs e)
    {
        // 画面が遷移する度に呼び出される
    }

    private void OnExited(object sender, ViewExitEventArgs e)
    {
        // Controller.Exit()した時に呼び出される
        Close();
    }
}

例えばMainFormに共通のヘッダ領域を配置し、各画面毎にその表示項目を更新したい場合等には、Forwardingイベントにその処理を記述します。
Forwardingイベントには、各画面遷移時に渡されるのと同じViewForwardEventArgsが渡されるので、どの画面への遷移かの情報をそこから取得できます(・∀・)
また、終了処理等はExitedイベントに記述します。

画面のイベント

IViewEventSupportを実装した画面は、画面オープン時にOnViewOpen()が呼び出され、画面クローズ時にOnViewClose()が呼び出されます。
なお、Controller.Push()による遷移を行う場合は、現在の画面のOnViewClose()は呼び出されません。
また、Controller.Pop()による遷移で戻ってきたときには、OnViewOpen()が再度呼び出されます。
ただし、ViewForwardEventArgs.IsPopBackにより初回かどうかの判定が可能です(・∀・)

[View(Views.ContextInput1)]
public partial class ContextInput1View : AppViewBase
{
    public override void OnViewOpen(ViewForwardEventArgs args)
    {
        // 画面の初期化処理
    }

    public override void OnViewClose()
    {
        // 画面の終了処理
    }
}

画面遷移時のパラメータ

画面遷移処理には下記のようなオーバーロードが存在し、遷移先の画面に対して任意のパラメータを渡すことが可能です。

public bool Forward(object id, params object[] parameters)

遷移先の画面では、ViewForwardEventArgs.Parametersによりparametersで指定した内容を取得できます。

public override void OnViewOpen(ViewForwardEventArgs args)
{
    object[] parameters = args.Parameters;
}

パラメータの引き継ぎ

画面遷移時にもパラメータは指定できますが、フィールドまたはプロパティに対してViewParameterAttributeを指定すると、次画面に対して自動的にパラメータを引き渡すことが可能です。

[View(Views.DataList)]
public partial class DataListView : AppViewBase
{
    [ViewParameter(Direction.Export)]
    protected string selectedId;

    private void EditButton_Click(object sender, EventArgs e)
    {
        // 引き継ぐパラメータを設定
        this.selectedId = "123";

        Controller.Push( Views.DataDetailEdit );
    }
}
[View(Views.DataDetailEdit)]
public partial class DataDetailView : AppViewBase
{
    [ViewParameter(Direction.Import)]
    protected string selectedId;

    public override void OnViewOpen(ViewForwardEventArgs args)
    {
        // 引き継がれたパラメータを取得
        Debug.Assert( this.selectedId == "123" );
    }
}

ViewParameterAttributeでは、同じ名称の変数に対して引き継ぎが行われます。
異なる名称の変数に対して引き継ぎを行いたい場合、ViewParameterAttribute.Nameプロパティを指定します。
また、ViewParameterAttribute.Directionプロパティにより、次画面への引き継ぎのみ(Direction.Export)、前画面からの引き継ぎのみ(Direction.Import)を指定できますが、デフォルトでは双方向(Direction.Both)となっています。

コンテキストのライフサイクル管理

下図のように、特定の画面間のみ使用したいデータがある場合には、対象となるデータクラスをフィールドまたはプロパティとし、ViewContextAttributeを付加することによりそのライフサイクル管理が可能となります(・∀・)


[View(Views.ContextInput1)]
public partial class ContextInput1View : AppViewBase
{
    [ViewContext]
    protected InputContext context;
...
}
[View(Views.ContextInput2)]
public partial class ContextInput2View : AppViewBase
{
    [ViewContext]
    protected InputContext context;
...
}
[View(Views.ContextConfirm)]
public partial class ContextConfirmView : AppViewBase
{
    [ViewContext]
    protected InputContext context;
...
}

この場合、InputContextのインスタンスは最初にViewContextAttributeが付加された画面へ遷移した時に生成され、ViewContextAttributeが存在しない画面へ遷移した時に破棄されます。
また、対象となるクラスに対してIContextSupportインタフェースを実装した場合、生成と破棄のタイミングでそれぞれInitilize()、Dispose()メソッドが呼び出されます。

public class InputContext : IContextSupport
{
    public string Data1 { get; set; }

    public string Data2 { get; set; }

    public void Initilize(ContextEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine( "*** InputContext Initilize ***" );
    }

    public void Dispose(ContextEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine( "*** InputContext Dispose ***" );
    }
}

画面外からの通知

画面外からControllerを通じて、現在表示している画面に対して通知が可能です。
通知はController.Notify()を通じて行います。

public partial class MainForm : Form
{
    private readonly Controller controller;
...
    private void OnButtonNotify(object sender, EventArgs e)
    {
        // 現在の画面に対して通知
        controller.Notify( Msg.Hoge );
    }
}
[View(Views.Hoge)]
public partial class HogeView : AppViewBase
{
...
    public override void OnViewNotify(Controller sender, ViewNotifyEventArgs args)
    {
        // 通知の取得
        object msg = args.Msg;
        object[] parameters = args.Paramters;
    }
}


…っというわけで、Smart.Windows.Mvcの機能はこんなところです(´д`)


まあ、画面遷移アプリのようなものを作る場合には、この手の基盤を用意した上で、画面内の制御のみに集中できるようにすべきですよ、っというお話です(・ω・)


ところで、Compact Framework版のプロジェクトに誤りがあることに気がついた(´д`;;)
アップロードしなおし…。