天天看點

Caliburn.Micro 傑的入門教程4,事件聚合器

Caliburn.Micro 傑的入門教程1(原創翻譯)

Caliburn.Micro 傑的入門教程2 ,了解Data Binding 和 Events(原創翻譯)

Caliburn.Micro 傑的入門教程3,事件和參數

Caliburn.Micro 傑的入門教程4,事件聚合器

Caliburn.Micro 傑的入門教程5,視窗管理器

Caliburn.Micro 傑的入門教程6, Screens 和 Conductors 簡介

 Caliburn Micro Part 4: The Event Aggregator

http://www.mindscapehq.com/blog/index.php/2012/2/1/caliburn-micro-part-4-the-event-aggregator/ 

在本周的教程中,我們将學習如何使用包含在Caliburn Micro中的”事件聚合器“。事件聚合器是很容易讓你的應用程式的多個部分發送消息給對方的服務。當你的應用程式有很多個view-models(視圖模型)需要溝通,這将非常有用。要做到這一點,需要先向事件聚合器訂閱你的對象(如view-models),并指定他們應該聽什麼類型的消息。你也可以定義(接收端)對象當收到這樣的消息會做些什麼。這樣,當應用程式的一端釋出的消息,事件聚合器可以確定比對的訂閱對象接受它,并執行相應的操作。在本教程中,我們将擴充我們以前做的入門示範代碼。 (你可以在這裡下載下傳。)

盡管事件聚合器是針對具有多個視圖模型較大的應用程式時會更有用,我們仍會保持我們的教程應用程式的最小化。要注意的是,本教程相比以前的教程,會更加難以消化!在本教程結束時,我們将有一個顯示兩個視圖,每個都有自己的視圖模型的應用程式。

View1視圖,将展示一些單選按鈕,分别代表不同的顔色。當單擊一個單選按鈕,我們将釋出消息,包括适當的顔色。

View2視圖,将偵聽這些消息并更改矩形的顔色。

我們将經曆4個步驟:為應用程式添加另一個視圖,實作IHandle<TMessage>接口,為一個ViewModel訂閱事件聚合器,最後另一個ViewModel視圖模型釋出事件。

Step 1: Adding Another View and View-Model(添加一個新的視圖和視圖模型)

為了說明該事件聚合器,我們的應用中需要至少2個視圖模型。我們已經有一個(AppViewModel),是以我們需要另外添加一個。還記得在入門教程中描述的命名約定?添加一個新類叫ColorViewModel,和一個名為ColorView使用者控件。我們也改變了ColorView的背景,使我們至少能看到點兒東西,當我們第一次将它添加到應用程式。在visual structure(視覺結構)方面,我們會擷取現有AppView以包含新ColorView。 (View視圖要使用事件聚合器并不需要進行嵌套)。一個ViewModel可以收聽從任何地方被發表在應用程式的消息)要做到這一點,AppViewModel需要類型ColorViewModel,我們設定的屬性構造函數是這樣的:

public class AppViewModel : PropertyChangedBase
{
  public AppViewModel(ColorViewModel colorModel)
  {
    ColorModel = colorModel;
  }
 
  public ColorViewModel ColorModel { get; private set; }
}      

在AppView.xaml中,我們将Grid網格分割成2列,第一列中的顯示ColorModelView。 AppView.xaml現在看起來像這樣:

<Grid Width="300" Height="300" Background="LightBlue">
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="*" />
    <ColumnDefinition Width="*" />
  </Grid.ColumnDefinitions>
  <ContentControl Name="ColorModel" Margin="10" />
</Grid>      

這裡的ContentControl的名稱是和我們剛剛添加到AppViewModel的名字一樣的。由此看來Caliburn Micro會很友好的為我們将ContentControl的Content屬性綁定到ColorModel屬性的。當我們運作這個了以後,Caliburn Micro将確定顯示ColorView的執行個體為ColorViewModel。

如果我們現在運作了該應用程式,我們會遇到一個異常說:AppViewModel的預設構造函數未發現。嗯,這是一個要點:我們已在AppViewModel的構造函數中指定了它需要一個參數 - 一個ColorViewModel對象。要解決這個問題,我們需要如下圖所示,更新我們的AppBootstrapper。 (請務必包括添加System.ComponentModel.Composition.dll到項目中。)

using Caliburn.Micro;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
 
public class AppBootstrapper : Bootstrapper<AppViewModel>
{
  private CompositionContainer container;
 
  protected override void Configure()
  {
    container = new CompositionContainer(new AggregateCatalog(AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()));
 
    CompositionBatch batch = new CompositionBatch();
 
    batch.AddExportedValue<IWindowManager>(new WindowManager());
    batch.AddExportedValue<IEventAggregator>(new EventAggregator());
    batch.AddExportedValue(container);
 
    container.Compose(batch);
  }
 
  protected override object GetInstance(Type serviceType, string key)
  {
    string contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;
    var exports = container.GetExportedValues<object>(contract);
 
    if (exports.Count() > 0)
    {
      return exports.First();
    }
 
    throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract));
  }
}      

和下載下傳Caliburn Micro時附帶的示例中使用的bootstrapper很相似。為了不使這個部落格文章太長了,我也不會深入介紹的這段代碼是幹什麼的(如果你需要更多的細節,可以搜尋MEF或Managed Extensibility Framework)。

接下來,我們需要給我們的兩個ViewModel類的屬性,添加”Export“(輸出)特性。這将用于AppBootstrapper中的GetInstance( )方法。

[Export(typeof(AppViewModel))]
public class AppViewModel : PropertyChangedBase
{
}
 
[Export(typeof(ColorViewModel))]
public class ColorViewModel
{
}      

最後,在AppViewModel的構造函數前,加入”ImportingConstructor“特性。這是為了表明,該構造函數應該被使用,因為沒有預設的構造函數。當Caliburn Micro建立AppViewModel時,它也将為我們創造ColorViewModel的執行個體傳遞到構造器。

[ImportingConstructor]
public AppViewModel(ColorViewModel colorModel)
{
   ColorModel = colorModel;
}      

現在,我們可以運作應用程式,看到成功顯示在AppView内的ColorView:

Caliburn.Micro 傑的入門教程4,事件聚合器

讓我們添加一個矩形到第二列。當傳遞了改變顔色的消息,這個矩形會改變顔色,是以它的顔色會在AppViewModel中對應一個屬性:

加入一個矩形:

<Rectangle Grid.Column="1" Width="100" Height="100" Fill="{Binding Color}" />      

矩形對應的屬性:

private SolidColorBrush _Color; 
public SolidColorBrush Color
{
  get { return _Color; }
  set
  {
    _Color = value;
    NotifyOfPropertyChange(() => Color);
  }
}      

Step 2: Implementing the IHandle<TMessage> Interface(實作IHandle<TMessage>接口)

我們将要在ColorViewModel釋出消息,在AppViewModel中捕獲消息。要做到這一點,我們将需要一個能容納資訊的類。這個類通常是非常小的和簡單的。它主要是需要有一些屬性,來容納我們要發送的任何資訊。下面是我們将要使用的消息類:

public class ColorEvent
{
  public ColorEvent(SolidColorBrush color)
  {
    Color = color;
  }
 
  public SolidColorBrush Color { get; private set; }
}      

為了讓AppViewModel來處理相應的事件,它需要實作IHandle<TMessage>接口。在我們的例子中,我們将使用ColorEvent作為它的泛型類型。該IHandle接口有一個”Handle“方法需要我們去實作。在我們的AppViewModel的Handle方法中,我們将處理發送來的ColorEvent中的SolidColorBrush,并用它來設定Color屬性。這将輪流改變矩形的視圖中的顔色:

public void Handle(ColorEvent message)
{
  Color = message.Color;
}      

Step 3: Subscribe(訂閱)

現在,我們需要向事件聚合器訂閱AppViewModel,以讓它可以真正偵聽釋出的消息。為此,我們需要給AppViewModel的構造函數增加另一個參數”IEventAggregator“。當一個AppViewModel建立時,Caliburn Micro就會傳遞給我們的引導程式設定的事件聚合器。現在,在構造函數中,我們簡單地調用像這樣的訂閱方法:

[ImportingConstructor]
public AppViewModel(ColorViewModel colorModel, IEventAggregator events)
{
  ColorModel = colorModel;
 
  events.Subscribe(this);
}      

Step 4: Publish(釋出)

ColorViewModel也需要事件聚合器,以便它可以釋出消息。添加一個構造函數,它需要一個IEventAggregator參數,并将其存儲在一個字段中。請記住,還要包括ImportingConstructor特性:

private readonly IEventAggregator _events; 
[ImportingConstructor]
public ColorViewModel(IEventAggregator events)
{
  _events = events;
}      

現在我們隻需要在ColorView中添加單選按鈕,傾聽他們的click事件,然後發出消息。你可能還記得在本系列的第二篇教程關于快速的方式來傾聽click事件。簡單地設定RadioButton單選的名稱,和我們想要要調用的方法簽名相同。我們當然可以使用事件參數,而不必為每個單選按鈕建立操作方法,但這裡我簡單清楚的做出來,這樣你就可以清楚地看到發生了什麼:

<RadioButton Name="Red" Content="Red" Foreground="White"
             VerticalAlignment="Center" HorizontalAlignment="Center" />
<RadioButton Name="Green" Content="Green" Foreground="White"
             VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="1" />
<RadioButton Name="Blue" Content="Blue" Foreground="White"
             VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="2" />      
public void Red()
{
  _events.Publish(new ColorEvent(new SolidColorBrush(Colors.Red)));
}
 
public void Green()
{
  _events.Publish(new ColorEvent(new SolidColorBrush(Colors.Green)));
}
 
public void Blue()
{
  _events.Publish(new ColorEvent(new SolidColorBrush(Colors.Blue)));
}      

就是這樣。現在運作應用程式并點選單選按鈕。看到AppViewModel成功獲得從ColorViewModel傳遞出的messgaes,改變矩形的顔色。

Caliburn.Micro 傑的入門教程4,事件聚合器

有一點要注意的是,我一直在身邊掠過SolidColorBrushes在消息設定矩形的顔色。一般來說,你會通過各地的原始值,然後使用轉換器在UI解釋價值對SolidColorBrush等。

完整版Visual Studio 2010項目在本教程中也可以從這裡下載下傳。我希望你找到的事件聚合器有用編排在應用程式跨不同的視圖模式通信。退房機制的文檔擷取更多資訊,包括如何做到多态事件訂閱,定制出版封送處理,并從事件聚合退訂。

有一點要注意的是,我一直傳遞的是SolidColorBrushes消息,用來設定矩形的顔色。一般來說,你要傳遞更多基元值,然後使用UI裡面的converter(轉換器)對SolidColorBrush解釋值。

-----以下為其他内容,和本節教程關系不大,就不自己翻譯修改了,請大體看看,如果需要請跳轉到原文:

繼續閱讀