2015-12-30 70 views
1

我已經開始編寫我的第一個WPF/MVVM,並且和其他人一樣發現,處理視圖之間的導航相當混亂。直接ViewModel切換的WPF/MVVM導航

我一直在尋找一段時間,大部分主題都推薦使用MVVM Light/PRISM,或者想出類似於here的解決方案。

我想要接近一個MVVM導航機制,我可以直接從一個視圖切換到另一個視圖(不使用父窗口中的數據模式切換)。比方說,我有一個主窗口加載來自不同usercontrols(視圖)的動態內容的應用程序。

MainWindowViewModel將具有指向UserListV的CurrentV屬性,以及指向UserListVM的CurrentVM屬性。現在,我從列表中選擇一個用戶,然後單擊「查看」按鈕在同一窗口的另一個屏幕中查看該用戶的詳細信息。這應該允許我使用UserVM作爲數據上下文切換到UserV。

我在想如何在UserListVM上調用MainWindowViewModel來更新CurrentV和CurrentVM值,並相應地將窗口切換到UserV?

任何建議更好的主意都是值得歡迎的!

非常感謝!

+0

您需要通過某種方式告知'MainWindowViewModel'將視圖更改爲Detail的視圖。您只能使用一個'CurrentViewModel'屬性來設置'UserList'或'User'視圖模型。視圖將由DataTemplate根據ViewModel的類型決定 – Fabio

+0

這就是我想要弄清楚的。沒有父佈局(我不想使用),我還沒有找到一種方法告訴M​​ainWindowVM從當前視圖更新它的CurrentViewModel。消息服務也許是我需要的。 – tab87vn

+0

消息或事件的方法都將是你的案例中足夠好的解決方案 – Fabio

回答

3

我使用消息傳遞服務在ViewModels之間進行通信,同時仍然保持它們的解耦。如果您使用的是MVVMLight,則附帶一個。我不想使用MVVM框架,並編寫我自己的消息服務。這是一個從最近的一個項目的例子:

public class MessageService : IMessageService 
{ 
    private List<IMessageSubscription> subscribers; //list of subscription objects registered 

    public MessageService() 
    { 
     subscribers = new List<IMessageSubscription>(); 
    } 

    public void Subscribe<T>(string message, Action<T> action) 
    { 
     subscribers.Add(new MessageSubscription<T>() 
     { 
      Message = message, 
      MessageActionWithArgs = action 
     }); 
    } 

    public void Subscribe(string message, Action action) 
    { 
     subscribers.Add(new MessageSubscription<bool>() 
     { 
      Message = message, 
      MessageActionNoArgs = action 
     }); 
    } 

    public void Send<T>(string message, T args) 
    { 
     IEnumerable<IMessageSubscription> matches = subscribers.Where(x => x.Message == message && x.PayLoadType == typeof(T)); 

     foreach (IMessageSubscription sub in matches.ToList()) 
     { 
      sub.InvokeMessageAction((T)args); 
     } 
    } 

    public void Send(string message) 
    { 
     IEnumerable<IMessageSubscription> matches = subscribers.Where(x => x.Message == message); 

     foreach (IMessageSubscription sub in matches.ToList()) 
     { 
      sub.InvokeMessageAction(); 
     } 
    } 
} 

因此,例如,MainViewModel會聽的消息,如「ActiveViewModelChangeRequest」,而當他們需要變得活躍等的ViewModels將發送該消息。所以,在MainViewModel你有這樣的事情:

public MainViewModel() 
{ 
    messageService.Register<ViewModelBase>("ActiveViewModelChangeRequest", UpdateActiveViewModel); 
} 

private void UpdateActiveViewModel(ViewModelBase viewModel) 
{ 
    this.CurrentVM = viewModel; 
} 

然後在UserListVM你會:

private void OnUserSelect(object sender, UserSelectionEventArgs e) 
{ 
    UserVM viewModel = new UserVM(SelectedUser); 
    messageService.Send<ViewModelBase>("ActiveViewModelChangeRequest, viewModel); 
} 

有大量的閱讀材料,可對MVVM應用的使者模式。我建議讀一下這個。

+0

似乎這就是我正在尋找的,以及MVVM light和PRISM的想法。與你類似,我不想使用任何這些框架,所以試圖自己寫一個。首先需要以任何方式理解消息服務。 IMessageSubscription和IMessageService有什麼特別的注意事項嗎? – tab87vn

+0

我會推薦使用PRISM,它與Unity/MEF容器和事件聚合器進行通信。 要回答你的問題:棱鏡支持RegionManager.RequestNavigat(navigationParams)...所以你可以很容易地切換到一個新的視圖和傳遞用戶信息作爲導航參數... 如果你使用任何你自己或thridparty的消息服務,你仍然必須編寫一些導航框架。 – WPFKK

+0

我實際上沒有選擇寫我自己的框架或使用微軟的官方庫。我知道,因爲我已經開始學習WPF的時間不到2周,所以從頭開始編寫一個可用的MVVM機制可能很麻煩。 PRISM是由MS還是由某人代表他們正式發佈的? – tab87vn