2014-04-21 69 views
2

我是Caliburn Micro的新成員,希望得到一些建議,以瞭解在應用界面和視圖之間導航的路徑。 我的想法是有一個MainWindow,它將包含一個按鈕菜單,每個按鈕與特定視圖相關。每個視圖都將存儲在一個獨立的WPF UserControl中。 mainWindow還將包含綁定到viewmodel上的選項卡的ObservableCollection的TabControl。每次點擊菜單上的按鈕,我想添加一個新的標籤,裏面有一個ContentPresenter,它將動態加載一個視圖及其相應的視圖模型。關於使用Caliburn.Micro MVVM進行視圖導航的建議WPF

所以我的問題:

1)我應該在這裏使用一個屏幕集合?

2)UserControl應該實現Screen接口嗎?

3)如何告訴MainWindow ViewModel哪個視圖要加載到新添加的選項卡上,保持viewmodels解耦?

感謝大家提前。

UPDATE

大量的閱讀和社區的一些幫助後,我設法解決這個問題。這是產生AppViewModel:

class AppViewModel : Conductor<IScreen>.Collection.OneActive 
{ 
    public void OpenTab(Type TipoVista) 
    { 
     bool bFound = false; 
     Screen myScreen = (Screen)Activator.CreateInstance(TipoVista as Type); 
     myScreen.DisplayName = myScreen.ToString(); 
     foreach(Screen miItem in Items) 
     { 
      if (miItem.ToString() == myScreen.ToString()) 
      { 
       bFound = true; 
       ActivateItem(miItem); 
      }     
     } 
     if (!bFound) ActivateItem(myScreen);   
    } 

    public ObservableCollection<MenuItem> myMenu { get; set; } 
    public ObservableCollection<LinksItem> myDirectLinks { get; set; } 

    public ICommand OpenTabCommand 
    { 
     get 
     {     
      return new RelayCommand(param => this.OpenTab((Type) param), null); 
     } 
    }  

    public AppViewModel() 
    { 
     OpenTab(typeof(ClientsViewModel));    
     MenuModel menu = new MenuModel(); 
     myMenu = menu.getMenu(); 
     myDirectLinks = menu.getLinks(); 
    }   

    public void CloseTab(Screen param) 
    {    
     DeactivateItem(param, true); 
    }  
} 

我不得不從OpenTabCommand保持ICommand的,因爲Caliburn.micro的命名規範似乎並不裏面的DataTemplate工作。希望它可以幫助別人。感謝所有

回答

3

我用Caliburn.Micro做了一些非常相似的事情,並根據示例中包含的SimpleMDI示例進行了一些調整,以適應我的需要。

就像在本例中,我有一個主ShellViewModel

public class ShellViewModel : Conductor<IScreen>.Collection.OneActive 
{ 
} 

與對應ShellView含有TabControl - <TabControl x:Name="Items">,它結合到所述ConductorItems屬性。

在這個特定的情況下,我也對我的ShellViewContextMenu,結合(使用Caliburn.Micro約定),以一系列的命令,其實例化,並Activated各種其它ViewModels(通常是用相應UserControl,關於使用ActivateItem方法該Conductor

public class YourViewModel: Conductor<IScreen>.Collection.OneActive 
{ 
    // ... 

    public void OpenItemBrowser() 
    { 
     // Create your new ViewModel instance here, or obtain existing instance. 
     // ActivateItem(instance) 
    } 
} 

在這種情況下,我沒有要求與任何特定的依賴要創建的ViewModels,或從程序中的任何其它位置。

在其他時間,當我需要從應用程序中的其他地方觸發ViewModel時,我已使用Caliburn.MicroEventAggregator來發布自定義事件(例如,它可以由實現相應接口的類來處理(例如,IHandle<OpenNewBrowser>),所以你的主要ViewModel可以有一個簡單的方法Handle負責打開所需View

public class YourViewModel: Conductor<IScreen>.Collection.OneActive, IHandle<OpenNewBrowser> 
{ 
    // ... 

    public void Handle(OpenNewBrowser myEvent) 
    { 
     // Create your new ViewModel instance here, or obtain existing instance. 
     // ActivateItem(instance) 
    } 
} 

的文件This section可能會是有用的,特別是簡單的MDI部分。

附加代碼我在評論中提到:

我有時使用一個通用的方法沿着這些線路確保如果我有一個特定類型的屏幕的現有實例,切換到它,或者創建一個新的實例如果不。

public void ActivateOrOpen<T>() where T : Screen 
{ 
    var currentItem = this.Items.FirstOrDefault(x => x.GetType() == typeof(T)); 

    if (currentItem != null) 
    { 
     ActivateItem(currentItem); 
    } 
    else 
    { 
     ActivateItem(Activator.CreateInstance<T>()); 
    } 
} 

使用,如:

public void OpenBrowser() 
{ 
    this.ActivateOrOpen<BrowserViewModel>(); 
} 
+0

非常感謝您!這正是我需要的!我自己做了一些測試,並且發現可以使SimpleMDI簡單適應我的需求。我唯一不同的是如何打開新的視圖(使用ActivateItem),因爲我有一個菜單,我想將每個菜單選項鍊接到特定視圖,所以我使用「Screen myScreen =(Screen)Activator.CreateInstance(ViewType as Type );」傳遞ViewType作爲視圖模型類類型的引用。如果你看到我的更新,我發佈我的AppViewModel。再次感謝你! – ericpap

+0

這很有道理= D我有時使用泛型方法來控制我只想要一個實例的屏幕,我會在一個編輯中發佈它,而不是試圖將其嵌入到這裏。 – Chris