2011-05-10 110 views
2

我對Prism很有新意,玩過一段時間後出現了一些問題。我試圖創建一個基本上包含在shell窗口中的地圖控件的模塊化應用程序。插件模塊提供了與地圖交互的不同工具。有些模塊相當獨立,只需在地圖上顯示引腳。WPF/Prism庫和多個shell

  • 第一個問題:RegionManager如何發揮必須與主地圖控件交互的模塊特定類(演示者)的作用?通常在RegionManager中註冊一個鏈接到ViewModel的特定視圖,但在我的情況下,有一個單獨的視圖(地圖視圖),其中有多個演示者在其上進行操作。

  • 第二個問題:我需要能夠打開幾個窗口(shell) - 有點像MS Word文檔 - 應該全部由插件模塊擴展。在單殼環境中,當模塊特定類被實例化時,他們可以使用依賴注入容器來獲取對RegionManager或Shell本身的引用,以便訪問地圖控件。但是,對於多個shell,我不知道如何訪問右殼的地圖控件。依賴容器具有對應用程序全局對象的引用,而不是特定於我目前正在使用的外殼。對於EventAggregator也是如此。

任何投入將是非常歡迎的,

埃德

+0

每個引腳都有獨立的模塊?不,男人,這不酷。模塊必須根據其功能而有所不同,但在這種特殊情況下,最好使用包含子視圖模型集合的視圖模型。接下來,第二個問題提供一些信息,顯示在自定義窗口中以及它們如何打開。我認爲有必要將引用存儲在全局對象中,但我不知道所有的細節,所以我現在還不能確切地說。 – vorrtex 2011-05-10 21:16:27

+0

不,不是每個引腳的模塊:)模塊應該註冊一個類(演示者),它將以某種方式被實例化並賦予Shell的地圖控件。然後它可以例如顯示城市中所有攝像頭的圖標。另一個模塊可以使用相同的地圖來顯示交通信息。這就是爲什麼這些模塊是獨特的,但應該與相同的「文檔 - 全球」地圖控制交互。 – Eduard 2011-05-10 22:29:44

+0

自定義窗口與打開新的Word文檔基本相同,但在我的情況下,它將是一個「地圖文檔」。基本上是初始shell的精確副本。因此,在一個窗口中,您可以啓用流量,並在另一個窗口中啓用相機信息(例如)。關於「他們是如何被打開的」,我正在考慮沿着「文件 - >新文檔」的方式。 – Eduard 2011-05-10 22:33:47

回答

1

你有一個主視圖和許多孩子的意見,以及兒童的意見可以通過不同的模塊來添加。

我不確定RegionManager類可以應用在這種情況下,所以我將創建一個單獨的全局類IPinsCollectionState 它必須在引導程序中註冊爲單例。

public interface IPin 
{ 
    Point Coordinates { get; } 
    IPinView View { get; } 
    //You can use a view model or a data template instead of the view interface, but this example is the simplest 
} 

public interface IPinsCollectionState 
{ 
    ObservableCollection<IPin> Pins { get; } 
} 

你的主視圖模型和不同的模塊可以接收該接口作爲構造參數:模塊視圖模型的

public class MapViewModel 
{ 
    public MapViewModel(IPinsCollectionState collectionState) 
    { 
     foreach (var item in collectionState.Pins) 
     { /* Do something */ }; 

     collectionState.Pins.CollectionChanged += (s, e) => {/* Handle added or removed items in the future */}; 
    } 

    //... 
} 

實施例:

public class Module1ViewModel 
{ 
    public Module1ViewModel(IPinsCollectionState collectionState) 
    { 
     //somewhere in the code 
     collectionState.Pins.Add(new Module1Pin()); 
    } 
} 

第二個問題是可以解決的以許多不同的方式:

  • Application.Current.Windows
  • 一個包含ShellViewModel列表的全局MainViewModel,如果添加新的視圖模型,它將顯示在新窗口中。引導程序對於所有窗口都是單獨的。
  • 傳遞給引導程序構造函數的某種共享狀態。

我不知道這些窗口是如何相互關聯的,我不知道哪種方式是最好的,也許有可能用獨立窗口編寫應用程序。

+0

如果我理解正確,我不會使用AutoRegisterBehavior註冊來自不同模塊的視圖。我基本上必須在創建新窗口時「手工創建」MapViewModel(s)。是否有意義?我會發佈一個我已經嘗試過的解決方案,似乎可以達到我想要的效果。告訴我,如果它是有道理的;) – Eduard 2011-05-11 15:02:58

+0

@Eduard這是什麼意思「手動」?如果你選擇第二個選項,你可以使用'容器。Resolve'方法,但是您必須將結果存儲在全局集合的某處。 – vorrtex 2011-05-11 15:17:31

+0

@vorrtex我發佈了我的解決方案。 「手工」是我不使用區域管理框架來創建實例...沒有AutoPopulateRegionBehavior。所以基本上我沒有使用Prism的那部分。此外,由於我的作用域統一容器,我不確定如何使用RegionManager.RegisterViewWithRegion()開箱即用。 – Eduard 2011-05-11 17:00:26

2

經過幾個小時的閱讀棱鏡相關的文章和論壇我碰到了Erwin van der Valk的博客 - How to Build an Outlook Style Application的文章「如何構建一個Outlook風格的應用程序」。

在架構的一部分中,使用了一個Unity子容器來解析類型實例。這正是我第二個問題的答案所需要的:我需要「範圍」(通過窗口)依賴注入(例如:窗口範圍的EventAggregator,地圖控件等)

以下是我如何創建一個新窗口:

private IShellWindow CreateNewShell(IRegionManager regionManager) 
{ 
    IUnityContainer childContainer = this.Container.CreateChildContainer(); 

    ... register types in child container ...  

    var window = new ShellWindow(); 
    RegionManager.SetRegionManager(window, regionManager); 
    window.Content = childContainer.Resolve<MapDocumentView>(); 
    return window; 
} 

因此,MapDocumentView及其所有組件都將被注入(如果需要)窗口範圍的實例。

既然我可以有範圍的注入對象,我可以在基於模塊的MapPresenter中獲取窗口範圍的地圖。爲了回答我的第一個問題,我定義了一個由具有MapPresenterRegistry屬性的Bootstrapper實現的接口IHostApplication。該界面被添加到主容器。
初始化後,模塊將註冊他們的演示者,並在創建窗口時,它們將被實例化。

所以對於模塊初始化:

public void Initialize() 
{ 
    ... 
    this.hostApplication.MapPresenterRegistry.Add(typeof(ModuleSpecificMapPresenter)); 
    ... 
} 

初始化地圖窗口中的代碼:

private void View_Loaded(object sender, RoutedEventArgs e) 
{ 
    // Register map in the == scoped container == 
    container.RegisterInstance<IMap>(this.View.Map); 

    // Create map presenters 
    var hostApplication = this.container.Resolve<IHostApplication>(); 
    foreach (var mapPresenterType in hostApplication.MapPresenterRegistry) 
    { 
    var mapPresenter = this.container.Resolve(mapPresenterType) as IMapPresenter; 
    if (mapPresenter != null) 
    { 
     this.mapPresenters.Add(mapPresenter); 
    } 
    } 
} 

與特定模塊MapPresenter:

public ModuleSpecificMapPresenter(IEventAggregator eventAggregator, IMap map) 
{ 
    this.eventAggregator = eventAggregator; 
    this.map = map; 
    this.eventAggregator.GetEvent<AWindowSpecificEvent>().Subscribe(this.WindowSpecificEventFired); 

    // Do stuff on with the map 
} 

因此,這些都是大我的解決方案的線。我不太喜歡的是我沒有這樣利用區域管理。我幾乎有自定義代碼來完成這項工作。

如果您有任何進一步的想法,我會很高興聽到他們。 Eduard