2013-03-06 73 views
5

我正在開發使用的WinRT Caliburn.Micro一個Windows應用商店的應用程序的遊戲,我依靠導航框架。如何使用WinRT Caliburn.Micro將參數傳遞給導航視圖模型?

我對遊戲的設置(定義播放器)和實際遊戲視圖模型。從設置導航到遊戲時,我想將玩家集合傳遞給遊戲視圖模型。我怎樣才能做到這一點?

示意,我的視圖模型目前是這樣的:

public class SetupGameViewModel : NavigationViewModelBase 
{ 
    public SetupGameViewModel(INavigationService ns) : base(ns) { } 

    public IObservableCollection<Player> Players { get; set; } 

    public void StartGame() 
    { 
     // This is as far as I've got... 
     base.NavigationService.NavigateToViewModel<GameViewModel>(); 

     // How can I pass the Players collection from here to the GameViewModel? 
    } 
} 

public class GameViewModel : NavigationViewModelBase 
{ 
    public GameViewModel(INavigationService ns) : base(ns) { } 

    public ScoreBoardViewModel ScoreBoard { get; private set; } 

    public void InitializeScoreBoard(IEnumerable<Player> players) 
    { 
     ScoreBoard = new ScoreBoardViewModel(players); 
    } 
} 

理想情況下,我想打電話給InitializeScoreBoard從構造函數中,但據我已經能夠告訴它是不可能的將SetupGameViewModel.Players集合傳遞給構造函數。

INavigationService.NavigateToViewModel<T>(擴展)方法可選地採用[object] parameter參數,但此參數似乎未達到導航到的視圖模型構造函數。而且我也不知道如何明確地調用SetupGameViewModel.StartGame方法中的GameViewModel.InitializeScoreBoard方法,因爲尚未在此階段初始化。

回答

4

最後,我通過實現一個臨時的事件處理程序解決了這個。事實證明,我可以使用超載來傳遞播放器集合。

Caliburn Micro discussion forumMSDN documentation我得到的印象是這種方法只能保證適用於「原始」類型,儘管在我的情況下我迄今沒有發現任何問題。

SetupGameViewModel.StartGame方法現在實現如下:

private static void NavigationServiceOnNavigated(object sender, NavigationEventArgs args) 
{ 
    FrameworkElement view; 
    GameViewModel gameViewModel; 
    if ((view = args.Content as FrameworkElement) == null || 
     (gameViewModel = view.DataContext as GameViewModel) == null) return; 

    gameViewModel.InitializeScoreBoard(args.Parameter as IEnumerable<Player>); 
} 

不是真正的清潔解決方案,我一直努力:

public void StartGame() 
{ 
    base.NavigationService.Navigated += NavigationServiceOnNavigated; 
    base.NavigationService.NavigateToViewModel<GameViewModel>(Players); 
    base.NavigationService.Navigated -= NavigationServiceOnNavigated; 
} 

而且非常如下暫時附着NavigationServiceOnNavigated事件處理程序實現因爲,但至少它似乎工作。

+1

謝謝你,它節省了我很多的時間。 – jimpanzer 2013-05-24 07:27:55

+0

在Rob自己的這篇文章中,他解釋說,這是因爲Windows Phone中基於導航的系統是基於Uri的,它不支持複雜的反序列化。 http://caliburnmicro.codeplex.com/discussions/267562 – 2013-09-04 14:58:34

6

OK,只是把它擺在那裏,Caliburn.Micro有統一的導航功能WP8和WinRT的:

NavigationService.UriFor<TargetViewModel>().WithParam(x => x.TargetProperty, ValueToPass).Navigate(); 

,你可以鏈WithParam多個參數。現在有一些限制,並非所有類型都經過了,我不太清楚確切的原因是什麼,但是WinRT中的導航工作方式有些問題。有人在Caliburn.Micro discussion section的某個地方提到過它。

無論如何,你可以用這種方式導航。不要依賴構造函數,它會調用OnInitializeOnActivate。所以,僅僅把它切成例如:

NavigationService.UriFor<DetailsViewModel>().WithParam(x => x.Id, SelectedDetailsId).Navigate(); 

然後在DetailsViewModel

protected override void OnInitialize() 
{ 
    //Here you'll have Id property initialized to 'SelectedDetailsId' from the previous screen. 
} 

所以,在純理論上說,你可以這樣做:

NavigationService.UriFor<GameViewModel>().WithParam(x => x.Players, Players).Navigate(); 
在設置

和那麼:

public class GameViewModel 
{ 
    public GameViewModel(INavigationService ns) : base(ns) 
    { 
     //It would probably be good to initialize Players here to avoid null 
    } 

    public ScoreBoardViewModel ScoreBoard { get; private set; } 

    public IObservableCollection<Player> Players {get;set;} 

    protected void OnInitialize() 
    { 
     //If everything goes as expected, Players should be populated now. 
     ScoreBoard = new ScoreBoard(Players); 
    } 
} 

In p儘管如此,我並不認爲傳遞像這樣的複雜構造(類集合等)將會起作用。

更原始類型的工作就好了(intstringDateTime等,但如URI沒有工作對我來說,總是null),所以最壞的情況/變通辦法,例如,序列化Players列表導航到臨時文件並將文件路徑作爲字符串傳遞給中的反序列化。

有人蔘與了漫遊SO的框架,他們可能會給你更有價值的見解。

+0

非常感謝,這是非常有用的信息,我學到了很多東西,從這個響應。然而,如你所懷疑的那樣,'Players'集合似乎不能通過'WithParam'來傳遞。我目前已經實現了一個非常尷尬的解決方案,我爲'Navigated'事件定義了一個本地處理程序。事件參數給出了導航內容,並且我隱含地認爲內容的'DataContext'是我的視圖模型。不過,如果有人爲此問題提供了更可靠的解決方案,那將是一件好事。 – 2013-03-06 16:32:41

+1

順便說一句,我想我找到了你所指的討論,[這裏](http://caliburnmicro.codeplex.com/discussions/393238)。 – 2013-03-06 16:38:32

+0

@AndersGustafsson是的,這就是這個討論。正如我所說的,目前我不清楚如何使用Caliburn.Micro解決方案,除了將數據保存在某個地方,然後通過某種密鑰重新創建它之外,從上述討論 - [甚至微軟勸阻](http://msdn.microsoft.com/en-us/library/windows/apps/hh702394.aspx),但它通常*支持* ... – 2013-03-06 19:56:53

2

在Win Store的應用程式可以交出用的NavigationService的幫助的ViewModels之間複雜的對象。只有在Silverlight應用程序中,您才被限制爲必須可序列化爲字符串的對象。 Win Store應用程序中不存在此限制。

在你的情況像下面應該工作。在StartGame()中,NavigationService用於調用GameViewModel。玩家名單作爲一個簡單的參數被移交。按照慣例,這個參數將被分配給目標ViewModel的屬性參數。

public class SetupGameViewModel : Screen 
{ 
    private readonly INavigationService _navigationService; 

    public MainPageViewModel(INavigationService navigationService) 
    { 
     _navigationService = navigationService; 
    } 

    public IObservableCollection<Player> Players { get; set; } 

    public void StartGame() 
    { 
     _navigationService.NavigateToViewModel<GameViewModel>(Players); 
    } 

    ... 
} 


public class GameViewModel : Screen 
{ 
    private IObservableCollection<Player> _parameter; 

    public IObservableCollection<Player> Parameter 
    { 
     get { return _parameter; } 
     set 
     { 
      if (value.Equals(_parameter)) return; 
      _parameter = value; 
      NotifyOfPropertyChange(() => Parameter); 
     } 
    } 

    protected override void OnActivate() 
    { 
     // do something with the player list 
     // ... 
    } 

    ... 
} 

關於這個問題的更詳細的信息可以在這裏找到:http://wp.qmatteoq.com/using-caliburn-micro-with-universal-windows-app-navigation/

+0

謝謝,這是我的Windows 10 UWP應用程序的答案。是的,目標視圖模型中的屬性(示例中爲「GameViewModel」)必須被稱爲「參數」 - 似乎是約定。 – 2016-09-10 11:35:59

相關問題