VB のたまご

作成日: 2017/05/14, 更新日: 2017/05/14



Navigation4

  •  引き続き、Navigation です。 ここでは、画面切り替え時に、データを渡す方法を学習します。

  •  まずは View です。 ListBox 内にある任意の項目を選択したタイミングで、コマンドを実行します。この時、選択項目をパラメータとして渡しておきます。 最終的には、下に配置している TabControl 内のページとして遷移してきて、選択項目の詳細データが表示されます。

  • <ListBox Name="listbox1" ItemsSource="{Binding People}">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="SelectionChanged">
                <prism:InvokeCommandAction 
                    Command="{Binding PersonSelectedCommand}" 
                    CommandParameter="{Binding ElementName=listbox1, Path=SelectedItem}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </ListBox>
    
    <TabControl 
        Grid.Row="1" 
        Margin="10" 
        prism:RegionManager.RegionName="PersonDetailsRegion" />
    

  •  対応する ViewModel です。 コマンドの処理で、View から受け取ったデータを、遷移処理でのパラメータに変換して、遷移先の画面に渡します。 ここでは、PersonDetailsRegion 区画に DetailView ユーザーコントロールをインジェクションするようにしていますね。

  • Public Property PersonSelectedCommand As DelegateCommand(Of PersonModel)
    
    <Dependency>
    Public Property Manager As IRegionManager
    
    ' コンストラクタ
    Public Sub New()
    
        Me.PersonSelectedCommand = New DelegateCommand(Of PersonModel)(AddressOf Me.PersonSelected)
        Me.CreatePeople()
    
    End Sub
    
    Private Sub PersonSelected(person As PersonModel)
    
        ' 選択した人データをパラメータとして準備
        ' パラメータから取得時に「person」というキー名を指定して取得したいので、キー名も登録
        Dim parameters = New NavigationParameters
        parameters.Add("person", person)
    
        ' タブページに表示
        If person IsNot Nothing Then
            Me.Manager.RequestNavigate("PersonDetailsRegion", "DetailView", parameters)
        End If
    
    End Sub
    

  •  DetailView ユーザーコントロールにバインドする ViewModel です。 渡されてきたパラメータは、IsNavigationTarget メソッドと OnNavigatedTo メソッド内で使っています。

  •  IsNavigationTarget メソッドでは、現在表示中のこの画面を再利用するか(アクティブに切り替えるか)、 新規作成して新しい画面として表示するか(新しいタブページとして表示するか)の判定に使っています。

  •  現在チェック中のインスタンス内で管理している SelectedPerson プロパティの値が渡されてきた値と一致する場合は、 以前表示している画面なので再利用しますし、一致しない場合は、また表示していない画面になるので、別インスタンスで作成して表示させます。

  • ' 本画面を再利用するかどうか
    Public Function IsNavigationTarget(navigationContext As NavigationContext) As Boolean Implements INavigationAware.IsNavigationTarget
    
        ' パラメータが渡されてきた場合、保持中の人データと今回選択した人データが一致するなら再利用、違うなら新規インスタンス生成
        ' 何も渡されていない場合、無条件で再利用
        Dim person = TryCast(navigationContext.Parameters("person"), PersonModel)
        If person IsNot Nothing Then
            Return (Me.SelectedPerson IsNot Nothing) AndAlso (Me.SelectedPerson.LastName = person.LastName)
        Else
            Return True
        End If
    
    End Function
    

  •  OnNavigatedTo メソッド内では、渡されてきた選択項目をクラスメンバーにセットして保持しておきます。 これは後から IsNavigationTarget メソッド内で評価対象として使われます。

  • ' 本画面に遷移してきた時の処理
    Public Sub OnNavigatedTo(navigationContext As NavigationContext) Implements INavigationAware.OnNavigatedTo
    
        Dim person = TryCast(navigationContext.Parameters("person"), PersonModel)
        If person IsNot Nothing Then
            Me.SelectedPerson = person
        End If
    
    End Sub
    
    ' 本画面から離れる時の処理
    Public Sub OnNavigatedFrom(navigationContext As NavigationContext) Implements INavigationAware.OnNavigatedFrom
    
    End Sub
    

  •  このサンプルを実行すると、画面上部にリストボックス、画面下部にタブコントロールが表示されます。 リストボックス内の項目を選択すると、タブコントロールに新規ページとして詳細画面が登録表示されます。

  •  すでに表示済みの項目であればそのタブページが再度アクティブに切り替わり、まだ表示していない項目であれば、 新規タブページとして登録表示されます。

  • スポンサーリンク


  •  それでは、以下ソース全体です。

  •  まずは、クラスライブラリです。

  •  PersonModel.vb

  • Imports Prism.Mvvm
    
    Namespace Models
    
        Public Class PersonModel
            Inherits BindableBase
    
            Private _FirstName As String
            Public Property FirstName() As String
                Get
                    Return _FirstName
                End Get
                Set(ByVal value As String)
                    Me.SetProperty(_FirstName, value)
                End Set
            End Property
    
            Private _LastName As String
            Public Property LastName() As String
                Get
                    Return _LastName
                End Get
                Set(ByVal value As String)
                    Me.SetProperty(_LastName, value)
                End Set
            End Property
    
            Private _Age As Integer
            Public Property Age() As Integer
                Get
                    Return _Age
                End Get
                Set(ByVal value As Integer)
                    Me.SetProperty(_Age, value)
                End Set
            End Property
    
            Private _LastUpdated As DateTime?
            Public Property LastUpdated() As DateTime?
                Get
                    Return _LastUpdated
                End Get
                Set(ByVal value As DateTime?)
                    Me.SetProperty(_LastUpdated, value)
                End Set
            End Property
    
            Public Overrides Function ToString() As String
                Return $"{Me.LastName}, {Me.FirstName}"
            End Function
    
        End Class
    
    End Namespace
    

  •  DetailViewModel.vb

  • Imports Prism.Mvvm
    Imports Prism.Regions
    Imports ClassLibrary1.Models
    
    Namespace ViewModels
    
        Public Class DetailViewModel
            Inherits BindableBase
            Implements INavigationAware
    
            Private _SelectedPerson As PersonModel
            Public Property SelectedPerson() As PersonModel
                Get
                    Return _SelectedPerson
                End Get
                Set(ByVal value As PersonModel)
                    Me.SetProperty(_SelectedPerson, value)
                End Set
            End Property
    
            ' コンストラクタ
            Public Sub New()
    
            End Sub
    
            ' 本画面を再利用するかどうか
            Public Function IsNavigationTarget(navigationContext As NavigationContext) As Boolean Implements INavigationAware.IsNavigationTarget
    
                ' パラメータが渡されてきた場合、保持中の人データと今回選択した人データが一致するなら再利用、違うなら新規インスタンス生成
                ' 何も渡されていない場合、無条件で再利用
                Dim person = TryCast(navigationContext.Parameters("person"), PersonModel)
                If person IsNot Nothing Then
                    Return (Me.SelectedPerson IsNot Nothing) AndAlso (Me.SelectedPerson.LastName = person.LastName)
                Else
                    Return True
                End If
    
            End Function
    
            ' 本画面に遷移してきた時の処理
            Public Sub OnNavigatedTo(navigationContext As NavigationContext) Implements INavigationAware.OnNavigatedTo
    
                Dim person = TryCast(navigationContext.Parameters("person"), PersonModel)
                If person IsNot Nothing Then
                    Me.SelectedPerson = person
                End If
    
            End Sub
    
            ' 本画面から離れる時の処理
            Public Sub OnNavigatedFrom(navigationContext As NavigationContext) Implements INavigationAware.OnNavigatedFrom
    
            End Sub
    
        End Class
    
    End Namespace
    

  •  DetailView.xaml
  •  画面クラスのコードビハインドには、名前空間の追加以外、処理はありません。

  • <UserControl x:Class="Views.DetailView"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 xmlns:local="clr-namespace:ClassLibrary1.Views"
                 xmlns:prism="http://prismlibrary.com/"
                 prism:ViewModelLocator.AutoWireViewModel="True"
                 mc:Ignorable="d" 
                 d:DesignHeight="300" d:DesignWidth="300">
    
        <Grid Background="White">
    
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
    
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
    
            <!-- First Name -->
            <TextBlock Text="First Name:" Margin="5" />
            <TextBlock Grid.Column="1" Margin="5" Text="{Binding SelectedPerson.FirstName}" />
    
            <!-- Last Name -->
            <TextBlock Grid.Row="1" Text="Last Name:" Margin="5" />
            <TextBlock Grid.Row="1" Grid.Column="1"  Margin="5" Text="{Binding SelectedPerson.LastName}" />
    
            <!-- Age -->
            <TextBlock Grid.Row="2" Text="Age:" Margin="5"/>
            <TextBlock Grid.Row="2" Grid.Column="1"  Margin="5" Text="{Binding SelectedPerson.Age}"/>
            
        </Grid>
    
    </UserControl>
    

  •  ClassLibrary1Module.vb

  • Imports Microsoft.Practices.Unity
    Imports Prism.Unity
    Imports Prism.Regions
    Imports Prism.Modularity
    Imports ClassLibrary1.Views
    
    Public Class ClassLibrary1Module
        Implements IModule
    
        <Dependency>
        Public Property Container As IUnityContainer
    
        Public Sub Initialize() Implements IModule.Initialize
    
            Me.Container.RegisterTypeForNavigation(Of DetailView)()
    
        End Sub
    
    End Class
    

    スポンサーリンク


  •  続いて、WPF アプリケーションプロジェクトです。

  •  Window1ViewModel.vb

  • Imports Microsoft.Practices.Unity ' Dependency 属性
    Imports Prism.Mvvm
    Imports Prism.Commands
    Imports Prism.Regions
    Imports System.Collections.ObjectModel
    Imports ClassLibrary1.Models
    
    Namespace ViewModels
    
        Public Class Window1ViewModel
            Inherits BindableBase
    
            Private _People As ObservableCollection(Of PersonModel)
            Public Property People() As ObservableCollection(Of PersonModel)
                Get
                    Return _People
                End Get
                Set(ByVal value As ObservableCollection(Of PersonModel))
                    _People = value
                End Set
            End Property
    
            Public Property PersonSelectedCommand As DelegateCommand(Of PersonModel)
    
            <Dependency>
            Public Property Manager As IRegionManager
    
            ' コンストラクタ
            Public Sub New()
    
                Me.PersonSelectedCommand = New DelegateCommand(Of PersonModel)(AddressOf Me.PersonSelected)
                Me.CreatePeople()
    
            End Sub
    
            Private Sub PersonSelected(person As PersonModel)
    
                ' 選択した人データをパラメータとして準備
                ' パラメータから取得時に「person」というキー名を指定して取得したいので、キー名も登録
                Dim parameters = New NavigationParameters
                parameters.Add("person", person)
    
                ' タブページに表示
                If person IsNot Nothing Then
                    Me.Manager.RequestNavigate("PersonDetailsRegion", "DetailView", parameters)
                End If
    
            End Sub
    
            ' 初期値登録
            Private Sub CreatePeople()
    
                Dim items = New List(Of PersonModel)
                For i As Integer = 0 To 10
                    items.Add(New PersonModel With
                              {
                              .FirstName = $"First {i}",
                              .LastName = $"Last {i}",
                              .Age = i
                              })
                Next
    
                Me.People = New ObservableCollection(Of PersonModel)(items)
    
            End Sub
    
        End Class
    
    End Namespace
    

  •  Window1.xaml
  •  画面クラスのコードビハインドには、名前空間の追加以外、処理はありません。

  • <Window x:Class="Views.Window1"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApplication1.Views"
            xmlns:prism="http://prismlibrary.com/"
            prism:ViewModelLocator.AutoWireViewModel="True"
            xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
            mc:Ignorable="d"
            Title="Window1" Height="350" Width="525">
    
        <!--
        ここで指定している DataContext は、TabControl にインジェクションしている DetailView にバインドしている DataContext のこと。
        つまり、DetailViewModel クラスの SelectedPerson プロパティ(の FirstName プロパティ)を指定している
        -->
        <Window.Resources>
            <Style TargetType="TabItem">
                <Setter Property="Header" Value="{Binding DataContext.SelectedPerson.FirstName}" />
            </Style>
        </Window.Resources>
    
        <Grid Background="White" Margin="10">
    
            <Grid.RowDefinitions>
                <RowDefinition Height="100" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
    
            <!--
            ListBox の SelectionChanged イベントが発生したら、
            PersonSelectedCommand コマンドを実行{選択中の項目(ListBox の SelectedItem)をパラメータとして渡す}
            SelectedItem プロパティには、Pople コレクションプロパティの1項目(PersonModel)がバインドされている
            -->
            <ListBox Name="listbox1" ItemsSource="{Binding People}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="SelectionChanged">
                        <prism:InvokeCommandAction 
                            Command="{Binding PersonSelectedCommand}" 
                            CommandParameter="{Binding ElementName=listbox1, Path=SelectedItem}" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </ListBox>
    
            <TabControl 
                Grid.Row="1" 
                Margin="10" 
                prism:RegionManager.RegionName="PersonDetailsRegion" />
    
        </Grid>
    
    </Window>
    

  •  Bootstrapper.vb

  • Imports Microsoft.Practices.Unity
    Imports Prism.Unity
    Imports Prism.Modularity
    Imports WpfApplication1.Views
    Imports ClassLibrary1
    Imports ClassLibrary1.Views
    
    Public Class Bootstrapper
        Inherits UnityBootstrapper
    
        ' Shell 担当になる View のインスタンスを返却
        Protected Overrides Function CreateShell() As DependencyObject
            Return Me.Container.Resolve(Of Window1)
        End Function
    
        ' Shell 担当になる View を表示
        Protected Overrides Sub InitializeShell()
            Application.Current.MainWindow.Show()
        End Sub
    
        ' モジュールカタログにモジュール情報を登録
        Protected Overrides Sub ConfigureModuleCatalog()
    
            Dim catalog = CType(Me.ModuleCatalog, ModuleCatalog)
            catalog.AddModule(GetType(ClassLibrary1Module))
    
        End Sub
    
    End Class
    

  •  Application.xaml.vb
  •  ※Application.xaml では、【StartupUri="MainWindow.xaml"】を削除しています。

  • Class Application
    
        ' Startup、Exit、DispatcherUnhandledException などのアプリケーション レベルのイベントは、
        ' このファイルで処理できます。
    
        Protected Overrides Sub OnStartup(e As StartupEventArgs)
            MyBase.OnStartup(e)
    
            ' Unity 管理による Prism アプリケーションの起動制御処理を実行
            Dim boot = New Bootstrapper
            boot.Run()
    
        End Sub
    
    End Class