簡體   English   中英

如何使用WinRT Caliburn.Micro將參數傳遞給導航視圖模型?

[英]How to pass parameter to navigated view model with WinRT Caliburn.Micro?

我正在使用WinRT Caliburn.Micro開發Windows應用商店應用游戲,我依賴於導航框架。

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

原理上,我的視圖模型目前看起來像這樣:

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從內GameViewModel構造,但據我已經能夠告訴它是不可能將通過SetupGameViewModel.Players收集到GameViewModel構造。

INavigationService.NavigateToViewModel<T> (擴展)方法可選地接受[object] parameter參數,但此參數似乎沒有到達導航到的視圖模型構造函數。 我無法弄清楚如何顯式調用GameViewModel.InitializeScoreBoard從方法SetupGameViewModel.StartGame方法,因為相關的GameViewModel尚未在這個階段初始化。

好吧,只是把它放在那里, Caliburn.Micro為WP8和WinRT統一導航:

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

您可以將WithParam到多個參數。 現在有一些限制,並非所有類型都經過,我不太清楚究竟是什么原因,但它有一些關於導航如何在WinRT中工作的事情。 Caliburn.Micro討論部分的某處提到了它。

無論如何,你可以這樣導航。 不要依賴於構造函數,它將調用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);
    }
}

但在實踐中,我並不認為傳遞像這樣的復雜結構(類等集合)會起作用。

更原始的類型工作得很好( intstringDateTime等,但是例如URI對我來說不起作用,總是為null ),因此最壞情況/解決方法是,例如,將Players列表序列化為temp導航前文件,並將該文件路徑字符串中的反序列化GameViewModel

有人更多地參與漫游SO的框架,他們可能會給你更多有價值的見解。

最后,我通過實現臨時事件處理程序解決了這個問題。 事實證明,我可以使用NavigateToViewModel<T>(object)重載來傳遞播放器集合。

Caliburn Micro論壇MSDN文檔中我得到的印象是這種方法只能保證適用於“原始”類型,盡管在我的場景中我到目前為止還沒有發現任何問題。

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

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

非常臨時附加的NavigationServiceOnNavigated事件處理程序實現如下:

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>);
}

不是我真正想要的干凈解決方案,但至少它似乎有效。

在Win Store應用程序中,您可以在NavigationService的幫助下在ViewModel之間移交復雜對象。 僅在Silverlight應用程序中,您才被限制為必須可序列化為字符串的對象。 Win Store應用程序中不存在此限制。

在你的情況下,類似下面的東西應該工作。 在StartGame()中,NavigationService用於調用GameViewModel。 播放器列表作為簡單參數移交。 按照慣例,此參數將分配給目標ViewModel的屬性Parameter。

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/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM