VB のたまご

作成日: 2017/03/20, 更新日: 2017/04/02



メッセンジャー(モーダル画面)

  •  (※もし、直接このページにたどり着いた方は、以前投稿した Livetアプリケーション作成時の注意 を読んで、 名前空間やプロジェクト追加に気を付ける必要があることを知ってください)

  •  続いてはモーダル画面の表示方法です。こういうのを作ります。

  • イメージ

  •  通常の画面の他に、モーダル表示させたい画面の合計2画面が登場しますので、ソースが多くなりますが、 前回のメッセージボックスと同じ処理の流れですので、難しくはありません。

  • スポンサーリンク


  •  最初は、Model 層です。 Models フォルダ内に、「Livet WPF4 モデル」を選択して、「PersonModel.vb」と言う名前でソースを作成したら、以下のように実装します。

  • Namespace Models
        Public Class PersonModel
            Inherits NotificationObject
    
            'NotificationObjectはプロパティ変更通知の仕組みを実装したオブジェクトです。
    
            ' コードスニペットを利用して楽に実装
            ' 変更通知プロパティ
            '「lpropn」→タブキーを押して確定、コードスニペットを挿入
            ' プロパティ名が選択されているので、任意の名称に変更。
            ' タブキーを押して、型を選択。任意の型に変更してエンターキーを押す。
    
    #Region "MyName変更通知プロパティ"
            Private _MyName As String
    
            Public Property MyName() As String
                Get
                    Return _MyName
                End Get
                Set(ByVal value As String)
                    If (_MyName = value) Then Return
                    _MyName = value
                    RaisePropertyChanged()
                End Set
            End Property
    #End Region
    
    #Region "Age変更通知プロパティ"
            Private _Age As Integer
    
            Public Property Age() As Integer
                Get
                    Return _Age
                End Get
                Set(ByVal value As Integer)
                    If (_Age = value) Then Return
                    _Age = value
                    RaisePropertyChanged()
                End Set
            End Property
    #End Region
    
            ' 等価演算子(=)は未対応だし、Equals メソッドは、参照先のアドレスを比較チェックしている
            ' そうではなくて、値同士の比較チェックによる等価チェックをしたいので、自前で用意(ViewModel のプロパティのセッターで使用)
            Public Function ValueEquals(other As PersonModel) As Boolean
    
                If other Is Nothing Then
                    Return False
                End If
    
                Return (Me.MyName = other.MyName) AndAlso (Me.Age = other.Age)
    
            End Function
    
        End Class
    End Namespace
    

  •  次は、ViewModel 層です。 ViewModels フォルダ内に、「Livet WPF4 ビュー・モデル」を選択して、「ModalWindow1ViewModel.vb」と言う名前でソースを作成したら、以下のように実装します。

  • Namespace ViewModels
        Public Class ModalWindow1ViewModel
            Inherits ViewModel
    
    #Region "Click1Command"
            Private _Click1Command As ViewModelCommand
    
            Public ReadOnly Property Click1Command() As ViewModelCommand
                Get
                    If _Click1Command Is Nothing Then
                        _Click1Command = New ViewModelCommand(AddressOf Click1)
                    End If
                    Return _Click1Command
                End Get
            End Property
    
            Private Sub Click1()
    
                Using vm = New ModalWindow2ViewModel
                    Messenger.Raise(New TransitionMessage(vm, "ShowModalWindow"))
    
                    ' モーダル画面の値を取得
                    Console.WriteLine($"MyName is 【{vm.Person.MyName}】, 【{vm.Person.Age}】 years old.")
    
                End Using
    
            End Sub
    #End Region
    
    
    
            Public Sub Initialize()
            End Sub
    
        End Class
    End Namespace
    

  •  2つ目のビューモデルです。 ViewModels フォルダ内に、「Livet WPF4 ビュー・モデル」を選択して、「ModalWindow2ViewModel.vb」と言う名前でソースを作成したら、以下のように実装します。

  • Imports w10_Messengers.Models
    
    Namespace ViewModels
        Public Class ModalWindow2ViewModel
            Inherits ViewModel
    
            ' コードスニペットを利用して楽に実装
            ' 変更通知プロパティ
            '「lpropn」→タブキーを押して確定、コードスニペットを挿入
            ' プロパティ名が選択されているので、任意の名称に変更。
            ' タブキーを押して、型を選択。任意の型に変更してエンターキーを押す。
    
    #Region "Person変更通知プロパティ"
            Private _Person As PersonModel = New PersonModel
    
            Public Property Person() As PersonModel
                Get
                    Return _Person
                End Get
                Set(ByVal value As PersonModel)
                    If _Person.ValueEquals(value) Then Return
                    _Person = value
                    RaisePropertyChanged()
                End Set
            End Property
    #End Region
    
    
    
            Public Sub Initialize()
            End Sub
    
        End Class
    End Namespace
    

    スポンサーリンク


  •  最後は、View 層です。 Views フォルダ内に、「Livet WPF4 ウィンドウ」を選択して、「ModalWindow1.xaml」と言う名前でソースを作成したら、以下のように実装します。

  • <Window x:Class="Views.ModalWindow1"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
            xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
            xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
            xmlns:v="clr-namespace:w10_Messengers.Views"
            xmlns:vm="clr-namespace:w10_Messengers.ViewModels"
            Title="ModalWindow1" Height="350" Width="525">
    
        <Window.DataContext>
            <vm:ModalWindow1ViewModel/>
        </Window.DataContext>
    
        <i:Interaction.Triggers>
    
            <!--WindowのContentRenderedイベントのタイミングでViewModelのInitializeメソッドが呼ばれます-->
            <i:EventTrigger EventName="ContentRendered">
                <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="Initialize"/>
            </i:EventTrigger>
    
            <!--Windowが閉じたタイミングでViewModelのDisposeメソッドが呼ばれます-->
            <i:EventTrigger EventName="Closed">
                <l:DataContextDisposeAction/>
            </i:EventTrigger>
    
            <!-- 
            モーダル表示したい画面、ViewModel から通知が来る
            そうしたら指定の型を持つ画面を、モーダルで、表示する
            Transition(トランジション)は、「遷移」という意味
            -->
            <l:InteractionMessageTrigger MessageKey="ShowModalWindow" Messenger="{Binding Messenger}">
                <l:TransitionInteractionMessageAction WindowType="{x:Type v:ModalWindow2}" Mode="Modal" />
            </l:InteractionMessageTrigger>
    
        </i:Interaction.Triggers>
    
        <StackPanel Margin="10">
    
            <Button Content="モーダル画面を表示" Command="{Binding Click1Command}" />
    
        </StackPanel>
    
    </Window>
    

    Namespace Views
        ' ViewModelからの変更通知などの各種イベントを受け取る場合は、PropertyChangedWeakEventListenerや
        ' CollectionChangedWeakEventListenerを使うと便利です。独自イベントの場合はLivetWeakEventListenerが使用できます。
        ' クローズ時などに、LivetCompositeDisposableに格納した各種イベントリスナをDisposeする事でイベントハンドラの開放が容易に行えます。
        '
        ' WeakEventListenerなので明示的に開放せずともメモリリークは起こしませんが、できる限り明示的に開放するようにしましょう。
        '
        Class ModalWindow1
    
        End Class
    End Namespace
    

  •  2つ目のビューです。 Views フォルダ内に、「Livet WPF4 ウィンドウ」を選択して、「ModalWindow2.xaml」と言う名前でソースを作成したら、以下のように実装します。

  • <Window x:Class="Views.ModalWindow2"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
            xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
            xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
            xmlns:v="clr-namespace:w10_Messengers.Views"
            xmlns:vm="clr-namespace:w10_Messengers.ViewModels"
            Title="ModalWindow2" Height="250" Width="425"
            WindowStartupLocation="CenterOwner">
    
        <!-- ↑画面の表示位置を、親画面の中央位置にセット -->
    
        <!-- バインドしたいビューモデルは、呼び出し元がセットしてくれるので、ここではバインドしない -->
        
        <i:Interaction.Triggers>
    
            <!--WindowのContentRenderedイベントのタイミングでViewModelのInitializeメソッドが呼ばれます-->
            <i:EventTrigger EventName="ContentRendered">
                <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="Initialize"/>
            </i:EventTrigger>
    
            <!--Windowが閉じたタイミングでViewModelのDisposeメソッドが呼ばれます-->
            <i:EventTrigger EventName="Closed">
                <l:DataContextDisposeAction/>
            </i:EventTrigger>
    
        </i:Interaction.Triggers>
    
        <Grid Margin="50">
    
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>
    
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="100" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
    
            <!-- 1行目 -->
            <TextBlock
                Text="名前:"
                HorizontalAlignment="Right"
                VerticalAlignment="Center"
                Grid.Row="0" Grid.Column="0" />
    
            <TextBox
                Text="{Binding Person.MyName}"
                VerticalContentAlignment="Center"
                Height="30"
                Grid.Row="0" Grid.Column="1" />
    
            <!-- 2行目 -->
            <TextBlock
                Text="年齢:"
                HorizontalAlignment="Right"
                VerticalAlignment="Center"
                Grid.Row="1" Grid.Column="0" />
    
            <TextBox
                Text="{Binding Person.Age}"
                VerticalContentAlignment="Center"
                Height="30"
                Grid.Row="1" Grid.Column="1" />
    
            <!-- 3行目 -->
            <Button
                Content="保存"
                Height="30"
                Grid.Row="2" Grid.Column="1">
    
                <!-- クリックしたら画面を閉じる -->
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Click">
                        <l:WindowInteractionMessageAction>
                            <l:DirectInteractionMessage>
                                <l:WindowActionMessage Action="Close" />
                            </l:DirectInteractionMessage>
                        </l:WindowInteractionMessageAction>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
    
            </Button>
    
        </Grid>
    
    </Window>
    

    Namespace Views
        ' ViewModelからの変更通知などの各種イベントを受け取る場合は、PropertyChangedWeakEventListenerや
        ' CollectionChangedWeakEventListenerを使うと便利です。独自イベントの場合はLivetWeakEventListenerが使用できます。
        ' クローズ時などに、LivetCompositeDisposableに格納した各種イベントリスナをDisposeする事でイベントハンドラの開放が容易に行えます。
        '
        ' WeakEventListenerなので明示的に開放せずともメモリリークは起こしませんが、できる限り明示的に開放するようにしましょう。
        '
        Class ModalWindow2
    
        End Class
    End Namespace
    

  •  このボタンの遷移順は以下の通りです。

  • イメージ

  •  メインは、Messenger に関わっている Modalwindow1 の画面処理です。