VB のたまご

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



EventAggregator1

  •  ここでは、EventAggregator(イベントアグリゲーター、イベント仲介サービス的なもの)について学習します。 想定するシナリオとしては、各モジュール間(お互い依存していない、参照を知らない)でのデータやり取りです。

  • イメージ
    スポンサーリンク


  •  通常、イベント処理を行いたい場合、イベント発行者がイベント購読者を知らないとイベント通知することができません。 以下は、ボタンのクリックイベントを購読するサンプルです。

  • AddHandler button1.Click, button1_Click
    

  •  button1.Click イベントは Form1 クラスにある button1_Click メソッドという直接参照を保持することで、通知を知らせることができます。 このイベントの考え方を依存無しで通知できるようにしたものが EventAggregator です。

  • イメージ
  •  イベント発信したい人とイベント受信したい人の間に入って仲介することで、お互いの参照を知らなくてもやり取りを可能にしています。 イベント発信したい人は、メソッドの中で「イベント1」というイベントを指定してイベント発生させて、データを渡します。 イベント受信したい人は、メソッドの中で「イベント1」というイベントを指定してイベント受信して、データを受け取ります。 両者は「イベント1」ということだけ知っていれば、やり取りできるわけです。

  •  ちょっと分かりにくい説明だと思いますので、コードを見てみましょう。 以下プロジェクト構成です。

  • イメージ
  •  最初は、共有イベントの作成です。 共有イベントは、Prism.Events.PubSubEvent クラスを使います。 この PubSubEvent というのは、Publisher(発行者) と Subscriber(購読者) の間でやり取りする Event から来ています。 扱う感じとしては、複数やり取りするイベントの中から、一意を識別できるキーと言う扱いで、ジェネリック引数となるイベントデータを渡すイメージです。

  • Public Class MessageSentEvent
        Inherits PubSubEvent(Of String)
    
    End Class
    

  •  メイン画面では、左右に1つずつ区画を予約しておいて、後から左右のモジュールをインジェクションします。 最初に、左側のモジュール(イベントを発信する側)です。 以下は ViewModel に記載したもので、Message は文字列のプロパティ、SendMessageCommand は DelegateCommand コマンドです。

  • <Dependency>
    Public Property Aggregator As IEventAggregator
    
    Public Sub New()
    
        ' メッセージを送信するイベント「MessageSentEvent」としてメッセージを送信(イベント発信)
        Me.SendMessageCommand =
            New DelegateCommand(Sub() Me.Aggregator.GetEvent(Of MessageSentEvent).Publish(Me.Message))
    
    End Sub
    

  •  イベント通知は、IEventAggregator インターフェースを使って操作します。 GetEvent メソッドで扱いたいイベントを指定して、その後 Publish メソッドで渡したいデータを指定しながらイベント発行します。

  •  発行されたイベントは受診しているところに通知されます。 以下は、右側のモジュール(イベントを受信する側)の ViewModel です。 Messages はコレクションプロパティで、受診したメッセージを履歴表示します。

  • Private Aggregator As IEventAggregator
    
    Public Sub New(_aggregator As IEventAggregator)
    
        Me.Aggregator = _aggregator
        Me.Messages = New ObservableCollection(Of String)
    
        ' 「MessageSentEvent」からのメッセージを受信(イベント受信)
        Me.Aggregator.GetEvent(Of MessageSentEvent)().Subscribe(Sub(x) Me.Messages.Add(x))
    
    End Sub
    

  •  受信側でも、GetEvent メソッドで扱いたいイベントを指定して、その後 Subscribe メソッドで渡されたデータを受け取って何らかの処理を行います。 ここでは通知データの履歴コレクションに登録しています。

  •  このサンプルを実行すると、左側に入力欄とボタン、右側に空欄のリストボックスが表示されます。 ボタンを押すことでメッセージが送信、受信されリストボックスに追加されていきます。

  • スポンサーリンク


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

  •  最初に、共有イベントを関するプロジェクト(クラスライブラリ)です。

  •  MessageSentEvent.vb

  • Imports Prism.Events
    
    ' メッセージを送信する共通イベント
    Public Class MessageSentEvent
        Inherits PubSubEvent(Of String)
    
    End Class
    

  •  続いて、イベント送信するプロジェクト(クラスライブラリ)です。

  •  MessageViewModel.vb

  • Imports Microsoft.Practices.Unity
    Imports Prism.Commands
    Imports Prism.Events
    Imports Prism.Mvvm
    Imports WpfApplication1.Common
    
    Namespace ViewModels
    
        Public Class MessageViewModel
            Inherits BindableBase
    
            Private _Message As String = "メッセージを送信"
            Public Property Message() As String
                Get
                    Return _Message
                End Get
                Set(ByVal value As String)
                    Me.SetProperty(_Message, value)
                End Set
            End Property
    
            Public Property SendMessageCommand As DelegateCommand
    
            <Dependency>
            Public Property Aggregator As IEventAggregator
    
            Public Sub New()
    
                ' メッセージを送信するイベント「MessageSentEvent」としてメッセージを送信(イベント発信)
                Me.SendMessageCommand =
                    New DelegateCommand(Sub() Me.Aggregator.GetEvent(Of MessageSentEvent).Publish(Me.Message))
    
            End Sub
    
        End Class
    
    End Namespace
    

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

  • <UserControl x:Class="Views.MessageView"
                 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"
                 Padding="25">
    
        <StackPanel>
            <TextBlock Text="Left Region" Margin="5" />
            <TextBox Text="{Binding Message}" Margin="5" />
            <Button Command="{Binding SendMessageCommand}" Content="メッセージ送信" Margin="5" />
        </StackPanel>
        
    </UserControl>
    

  •  ClassLibrary1Module.vb

  • Imports Microsoft.Practices.Unity
    Imports Prism.Regions
    Imports Prism.Modularity
    Imports ClassLibrary1.Views
    
    Public Class ClassLibrary1Module
        Implements IModule
    
        <Dependency>
        Public Property Manager As IRegionManager
    
        Public Sub Initialize() Implements IModule.Initialize
    
            Me.Manager.RegisterViewWithRegion("LeftRegion", GetType(MessageView))
    
        End Sub
    
    End Class
    

  •  続いて、イベント受信するプロジェクト(クラスライブラリ)です。

  •  MessageListViewModel.vb

  • Imports Prism.Events
    Imports Prism.Mvvm
    Imports System.Collections.ObjectModel
    Imports WpfApplication1.Common
    
    Namespace ViewModels
    
        Public Class MessageListViewModel
            Inherits BindableBase
    
            Private _Messages As ObservableCollection(Of String)
            Public Property Messages() As ObservableCollection(Of String)
                Get
                    Return _Messages
                End Get
                Set(ByVal value As ObservableCollection(Of String))
                    _Messages = value
                End Set
            End Property
    
            Private Aggregator As IEventAggregator
    
            Public Sub New(_aggregator As IEventAggregator)
    
                Me.Aggregator = _aggregator
                Me.Messages = New ObservableCollection(Of String)
    
                ' 「MessageSentEvent」からのメッセージを受信(イベント受信)
                Me.Aggregator.GetEvent(Of MessageSentEvent)().Subscribe(Sub(x) Me.Messages.Add(x))
    
            End Sub
    
        End Class
    
    End Namespace
    

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

  • <UserControl x:Class="Views.MessageList"
                 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:ClassLibrary2.Views"
                 xmlns:prism="http://prismlibrary.com/"
                 prism:ViewModelLocator.AutoWireViewModel="True"
                 Padding="25">
    
        <DockPanel LastChildFill="True">
            <TextBlock DockPanel.Dock="Top" Text="Right Region" Margin="5" />
            <ListBox ItemsSource="{Binding Messages}" />
        </DockPanel>
    
    </UserControl>
    
    

  •  ClassLibrary2Module.vb

  • Imports Prism.Modularity
    Imports Prism.Regions
    Imports ClassLibrary2.Views
    
    Public Class ClassLibrary2Module
        Implements IModule
    
        Private Manager As IRegionManager
    
        Public Sub New(_manager As IRegionManager)
            Me.Manager = _manager
        End Sub
    
        Public Sub Initialize() Implements IModule.Initialize
            Me.Manager.RegisterViewWithRegion("RightRegion", GetType(MessageList))
        End Sub
    
    End Class
    

  •  最後に、Shell を持つプロジェクト(WPF アプリケーション)です。

  •  Window1ViewModel.vb

  • Imports Prism.Mvvm
    
    Namespace ViewModels
    
        Public Class Window1ViewModel
            Inherits BindableBase
    
            Private _Title As String = "Prism Unity Application"
            Public Property Title() As String
                Get
                    Return _Title
                End Get
                Set(ByVal value As String)
                    _Title = value
                End Set
            End Property
    
        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"
            mc:Ignorable="d"
            Title="{Binding Title}" Height="350" Width="525">
    
        <Grid>
    
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
    
            <ContentControl
                Grid.Column="0"
                prism:RegionManager.RegionName="LeftRegion" />
    
            <ContentControl
                Grid.Column="1"
                prism:RegionManager.RegionName="RightRegion" />
    
        </Grid>
    
    </Window>
    

  •  Bootstrapper.vb

  • Imports Microsoft.Practices.Unity
    Imports Prism.Unity
    Imports Prism.Modularity
    Imports WpfApplication1.Views
    Imports ClassLibrary1
    Imports ClassLibrary2
    
    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))
            catalog.AddModule(GetType(ClassLibrary2Module))
    
        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