2015-10-14 98 views
4

我的Android應用程序中有以下代碼,它基本上使用一個頁面(使用NavigationDrawer)並將片段交換到中央視圖中。這允許出現一個頁面,而不是許多網頁上的導航:如何在Windows UWP中實現自定義演示者(Xamarin,MvvmCross)

Setup.cs:

protected override IMvxAndroidViewPresenter CreateViewPresenter() 
    { 
     var customPresenter = new MvxFragmentsPresenter(); 
     Mvx.RegisterSingleton<IMvxFragmentsPresenter>(customPresenter); 
     return customPresenter; 
    } 

ShellPage.cs

public class ShellPage : MvxCachingFragmentCompatActivity<ShellPageViewModel>, IMvxFragmentHost 
    { 
     . 
     . 
     . 

     public bool Show(MvxViewModelRequest request, Bundle bundle) 
     { 
      if (request.ViewModelType == typeof(MenuContentViewModel)) 
      { 
       ShowFragment(request.ViewModelType.Name, Resource.Id.navigation_frame, bundle); 
       return true; 
      } 
      else 
      { 
       ShowFragment(request.ViewModelType.Name, Resource.Id.content_frame, bundle, true); 
       return true; 
      } 
     } 

     public bool Close(IMvxViewModel viewModel) 
     { 
      CloseFragment(viewModel.GetType().Name, Resource.Id.content_frame); 
      return true; 
     } 

     . 
     . 
     . 
    } 

我怎樣才能實現在Windows UWP相同的行爲應用程序嗎?或者說,是否存在任何實現CustomPresenter的Windows MvvmCross應用程序的例子?這至少可以讓我開始如何實施它。

謝謝!

UPDATE:

我終於開始弄清楚如何去這與客戶主持人:

public class CustomPresenter : IMvxWindowsViewPresenter 
    { 
     IMvxWindowsFrame _rootFrame; 

     public CustomPresenter(IMvxWindowsFrame rootFrame) 
     { 
      _rootFrame = rootFrame; 
     } 

     public void AddPresentationHintHandler<THint>(Func<THint, bool> action) where THint : MvxPresentationHint 
     { 
      throw new NotImplementedException(); 
     } 

     public void ChangePresentation(MvxPresentationHint hint) 
     { 
      throw new NotImplementedException(); 
     } 

     public void Show(MvxViewModelRequest request) 
     { 
      if (request.ViewModelType == typeof(ShellPageViewModel)) 
      { 
       //_rootFrame?.Navigate(typeof(ShellPage), null); // throws an exception 

       ((Frame)_rootFrame.UnderlyingControl).Content = new ShellPage(); 
      } 
     } 
    } 

當我嘗試做一個導航到ShellPage,它失敗。所以,當我將內容設置爲ShellPage時,它工作正常,但是當我這樣做時,ShellPage的ViewModel不會自動初始化。我猜ViewModels在MvvmCross中使用OnNavigatedTo進行初始化?

+0

嘗試使用** ** ContentPresenter或者 –

+0

使用** **幀我 –

+0

需要知道如何與MvxWindowsStorePage在MvvmCross管理導航。 – Maximus

回答

7

我遇到了同樣的問題,併爲UWP構建了一個自定義演示者。它從我發現某處使用碎片的Android樣本中借了幾個想法。這個想法如下。

我有一個容器視圖,可以包含多個子視圖與自己的ViewModels。所以我想能夠在容器中呈現多個視圖。

注:我使用MvvmCross 4.0.0-β3

演示

using System; 
using Cirrious.CrossCore; 
using Cirrious.CrossCore.Exceptions; 
using Cirrious.MvvmCross.ViewModels; 
using Cirrious.MvvmCross.Views; 
using Cirrious.MvvmCross.WindowsUWP.Views; 
using xxxxx.WinUniversal.Extensions; 

namespace xxxxx.WinUniversal.Presenters 
{ 
    public class MvxWindowsMultiRegionViewPresenter 
     : MvxWindowsViewPresenter 
    { 
     private readonly IMvxWindowsFrame _rootFrame; 

     public MvxWindowsMultiRegionViewPresenter(IMvxWindowsFrame rootFrame) 
      : base(rootFrame) 
     { 
      _rootFrame = rootFrame; 
     } 

     public override async void Show(MvxViewModelRequest request) 
     { 
      var host = _rootFrame.Content as IMvxMultiRegionHost; 
      var view = CreateView(request); 

      if (host != null && view.HasRegionAttribute()) 
      { 
       host.Show(view as MvxWindowsPage); 
      } 
      else 
      { 
       base.Show(request); 
      } 
     } 

     private static IMvxWindowsView CreateView(MvxViewModelRequest request) 
     { 
      var viewFinder = Mvx.Resolve<IMvxViewsContainer>(); 

      var viewType = viewFinder.GetViewType(request.ViewModelType); 
      if (viewType == null) 
       throw new MvxException("View Type not found for " + request.ViewModelType); 

      // Create instance of view 
      var viewObject = Activator.CreateInstance(viewType); 
      if (viewObject == null) 
       throw new MvxException("View not loaded for " + viewType); 

      var view = viewObject as IMvxWindowsView; 
      if (view == null) 
       throw new MvxException("Loaded View is not a IMvxWindowsView " + viewType); 

      view.ViewModel = LoadViewModel(request); 

      return view; 
     } 

     private static IMvxViewModel LoadViewModel(MvxViewModelRequest request) 
     { 
      // Load the viewModel 
      var viewModelLoader = Mvx.Resolve<IMvxViewModelLoader>(); 

      return viewModelLoader.LoadViewModel(request, null); 
     } 
    } 
} 

IMvxMultiRegionHost

using Cirrious.MvvmCross.ViewModels; 
using Cirrious.MvvmCross.WindowsUWP.Views; 

namespace xxxxx.WinUniversal.Presenters 
{ 
    public interface IMvxMultiRegionHost 
    { 
     void Show(MvxWindowsPage view); 

     void CloseViewModel(IMvxViewModel viewModel); 

     void CloseAll(); 
    } 
} 

RegionAttribute

using System; 

namespace xxxxx.WinUniversal.Presenters 
{ 
    [AttributeUsage(AttributeTargets.Class)] 
    public sealed class RegionAttribute 
     : Attribute 
    { 
     public RegionAttribute(string regionName) 
     { 
      Name = regionName; 
     } 

     public string Name { get; private set; } 
    } 
} 

這些都是你需要三個基本類別。接下來,您需要在MvxWindowsPage派生類中實現IMvxMultiRegionHost

這是我使用的一個:

HomeView.xaml.cs

using System; 
using System.Diagnostics; 
using System.Linq; 
using Windows.Foundation; 
using Windows.UI.Xaml; 
using Windows.UI.Xaml.Controls; 
using Windows.UI.Xaml.Navigation; 
using Cirrious.MvvmCross.ViewModels; 
using Cirrious.MvvmCross.WindowsUWP.Views; 
using xxxxx.Shared.Controls; 
using xxxxx.WinUniversal.Extensions; 
using xxxxx.WinUniversal.Presenters; 
using xxxxx.Core.ViewModels; 

namespace xxxxx.WinUniversal.Views 
{ 
    public partial class HomeView 
     : MvxWindowsPage 
     , IMvxMultiRegionHost 
    { 
     public HomeView() 
     { 
      InitializeComponent(); 
     } 

     // ... 

     public void Show(MvxWindowsPage view) 
     { 
      if (!view.HasRegionAttribute()) 
       throw new InvalidOperationException(
        "View was expected to have a RegionAttribute, but none was specified."); 

      var regionName = view.GetRegionName(); 

      RootSplitView.Content = view; 
     } 

     public void CloseViewModel(IMvxViewModel viewModel) 
     { 
      throw new NotImplementedException(); 
     } 

     public void CloseAll() 
     { 
      throw new NotImplementedException(); 
     } 
    } 
} 

的最後一塊,使這項工作是在視圖中的實際XAML是SET-方式向上。您會注意到我正在使用SplitView控件,並且我正在使用HomeView類中的ShowView方法中的新視圖替換Content屬性。

HomeView.xaml

<SplitView x:Name="RootSplitView" 
      DisplayMode="CompactInline" 
      IsPaneOpen="false" 
      CompactPaneLength="48" 
      OpenPaneLength="200"> 
    <SplitView.Pane> 
     // Some ListView with menu items. 
    </SplitView.Pane> 
    <SplitView.Content> 
     // Initial content.. 
    </SplitView.Content> 
</SplitView> 

編輯:

擴展方法

我忘了後兩種擴展方法,以確定是否認爲一個聲明[Region] attribu TE。

public static class RegionAttributeExtentionMethods 
{ 
    public static bool HasRegionAttribute(this IMvxWindowsView view) 
    { 
     var attributes = view 
      .GetType() 
      .GetCustomAttributes(typeof(RegionAttribute), true); 

     return attributes.Any(); 
    } 

    public static string GetRegionName(this IMvxWindowsView view) 
    { 
     var attributes = view 
      .GetType() 
      .GetCustomAttributes(typeof(RegionAttribute), true); 

     if (!attributes.Any()) 
      throw new InvalidOperationException("The IMvxView has no region attribute."); 

     return ((RegionAttribute)attributes.First()).Name; 
    } 
} 

希望這會有所幫助。

+0

哇,我認爲這正是我正在尋找的答案。我會盡快嘗試,並報告給你。謝謝!! – Maximus

+0

好吧,所以我現在得到的唯一錯誤是「HasRegionAttribute」,它似乎在您的代碼中缺失。我如何添加該功能? – Maximus

+0

更新了原始答案以包含擴展方法。 – Stephanvs

1

爲紐帶@Stephanvs的博客不再是活動的,我能夠拉斷Web檔案的內容,我會在這裏張貼了;誰是尋找它:

實施多區演示的Windows 10 UWP和MvvmCross 2015年10月18日上MvvmCross,Xamarin,UWP時,Windows 10,主持人 通用Windows平臺

我升級Windows商店應用到新的Windows 10的通用Windows平臺。 MvvmCross在v4.0-beta2中增加了對UWP的支持。

UWP中的新控件是SplitView控件。基本上它作爲一個容器視圖,它由兩個子視圖組成,並排顯示。大多數情況下它用於實現(在)着名的漢堡菜單。

默認情況下,MvvmCross不知道如何處理SplitView,並在ViewModels之間導航時用新視圖替換整個屏幕內容。但是,如果我們想要以不同的方式佈置視圖並在一個窗口中顯示多個視圖,那麼我們需要一個不同的解決方案。幸運的是,我們可以插入一個自定義主持人,這將負責處理每個平臺的佈局。 註冊MultiRegionPresenter

在UWP項目的Setup.cs文件中,您可以使用以下實現重寫CreateViewPresenter方法。

`protected override IMvxWindowsViewPresenter CreateViewPresenter(IMvxWindowsFrame rootFrame) 
{ 
    return new MvxWindowsMultiRegionViewPresenter(rootFrame); 
}` 

使用區域

我們可以通過聲明一個元素定義的區域。此時它必須是Frame類型,因爲那樣我們在切換視圖時也可以顯示一個漂亮的過渡動畫。

`<mvx:MvxWindowsPage ...> 
    <Grid> 
     <!-- ... --> 

     <SplitView> 
      <SplitView.Pane> 
       <!-- Menu Content as ListView or something similar --> 
      </SplitView.Pane> 
      <SplitView.Content> 
       <Frame x:Name="MainContent" /> 
      </SplitView.Content> 
     </SplitView> 
    </Grid> 
</mvx:MvxWindowsPage> ` 

現在,我們希望能夠當一個ShowViewModel(...)發生換出在搜索Maincontent框架提出的最新觀點。 在一個區域中顯示視圖

在View的代碼隱藏中,我們現在可以聲明一個MvxRegionAttribute,定義我們希望在哪個區域渲染此視圖。該名稱必須與視圖中的框架元素相匹配。

`[MvxRegion("MainContent")] 
public partial class PersonView 
{ 
    // ... 
}` 

也可以在同一視圖內聲明多個區域。這將允許您將UI分成更多可重用的部分。 動畫化內容視圖之間的轉換

如果您希望在幀之間的視圖之間切換時有一個很好的動畫,可以將以下片段添加到幀聲明。

`<Frame x:Name="MainContent"> 
    <Frame.ContentTransitions> 
     <TransitionCollection> 
      <NavigationThemeTransition> 
        <NavigationThemeTransition.DefaultNavigationTransitionInfo> 
         <EntranceNavigationTransitionInfo /> 
       </NavigationThemeTransition.DefaultNavigationTransitionInfo> 
      </NavigationThemeTransition> 
     </TransitionCollection> 
    </Frame.ContentTransitions> 
</Frame>` 

導航時內容現在會很好動畫。

希望這有助於 Stephanvs

相關問題