2012-04-20 7 views
4

Я пытаюсь использовать TabActivity с MvvmCross, но я получаю NullReferenceException в рамочном коде, потому что viewModelLoader передаваемым в OnViewCreate равна нулюКак использовать MonoDroid TabActivity с использованием фреймворка MvvmCross

namespace Cirrious.MvvmCross.ExtensionMethods 
{ 
    public static class MvxViewExtensionMethods 
    { 
     public static void OnViewCreate<TViewModel>(this IMvxView<TViewModel> view, Func<TViewModel> viewModelLoader) 
      where TViewModel : class, IMvxViewModel 
     { 
      if (view.ViewModel != null) 
       return; 

      var viewModel = viewModelLoader(); 
      viewModel.RegisterView(view); 
      view.ViewModel = (TViewModel)viewModel; 
     } 

I Подозреваю, что это связано с тем, что я пытаюсь загрузить изображения напрямую, а не через ViewModel. Код в моей TabHost Activity выглядит так:

[Activity(Label = "TabHost")] 
    public class TabHostView : MvxBindingTabActivityView<TabHostViewModel> 
    { 
     protected override void OnViewModelSet() 
     { 
      SetContentView(Resource.Layout.Page_TabHostView); 
      var tabHostWidget = this.TabHost; 

      TabHost.TabSpec spec;  // Resusable TabSpec for each tab 
      Intent intent;   // Reusable Intent for each tab 
      // Create an Intent to launch an Activity for the tab (to be reused) 
      intent = new Intent(this, typeof(HomeView)); 
      intent.AddFlags(ActivityFlags.NewTask); 

      // Initialize a TabSpec for each tab and add it to the TabHost 
      spec = tabHostWidget.NewTabSpec("home"); 
      spec.SetIndicator("Home", Resources.GetDrawable(Resource.Drawable.icon_home)); 
      spec.SetContent(intent); 
      tabHostWidget.AddTab(spec); 
//... more tabs 

Как мне решить эту проблему?

Также мои ViewModels настроены так, что TabHostViewModel имеет свойство для каждой закладки ViewModel. Они ленивы в том, что они получают только данные из Модели, когда вызывается запрос доступа для свойства.

Итак, если у меня есть привязка данных в макетах axml на вкладке, предположительно, путь должен предполагать, что TabHostViewModel - это контекст (корень)?

Большое спасибо, Jason

ответ

6

На тривиальной уровне я думаю, вы могли бы быть в состоянии решить текущую проблему, задавая рамки, чтобы создать намерение для вас:

 TabHost.TabSpec spec;  // Resusable TabSpec for each tab 
     Intent intent;   // Reusable Intent for each tab 
     // Create an Intent to launch an Activity for the tab (to be reused) 
     intent = base.CreateIntentFor<HomeViewModel>(); 
     intent.AddFlags(ActivityFlags.NewTask); 

В более полный уровень ...


Существует не один способ занимать вкладки - как в Android, так и в MvvmCross.

В Android вы решите заняться TabActivity, используя макет, который непосредственно содержит все axml для представлений внутри каждой отдельной вкладки. Если вы работаете с этим методом, то I верьте, что вы можете просто использовать привязку данных напрямую, как обычно, - каждая отдельная вкладка должна работать так же, как ее обычный дочерний Android-виджет/просмотр ... Я читал, что там являются преимуществами производительности при работе с вкладками Android, но, как правило, я не работаю так.

Во-вторых - как я обычно работаю - вы можете решать TabActivity, рассматривая каждую вкладку как отдельную активность и связывая каждую из этих операций с дочерней ViewModel главной вкладки ViewModel. (Я попытаюсь нарисовать картину этой структуры и загрузить его позже сегодня!)

Если вы решите сделать это, то хороший пример для подражания является конференция один - https://github.com/slodge/MvvmCross/blob/master/Sample%20-%20CirriousConference/Cirrious.Conference.UI.Droid/Views/HomeView.cs

Что происходит в этом пример конференции, является то, что вкладка характеристика инициализируется с помощью spec.SetContent(intent), где намерение создаются с помощью вкладки активности метода базового класса CreateIntentFor - здесь соответствующий код:

protected override void OnViewModelSet() 
    { 
     SetContentView(Resource.Layout.Page_Home); 

     TabHost.TabSpec spec;  // Resusable TabSpec for each tab 
     Intent intent;   // Reusable Intent for each tab 

     // Initialize a TabSpec for each tab and add it to the TabHost 
     spec = TabHost.NewTabSpec("welcome"); 
     spec.SetIndicator(this.GetText("Welcome"), Resources.GetDrawable(Resource.Drawable.Tab_Welcome)); 
     spec.SetContent(CreateIntentFor(ViewModel.Welcome)); 
     TabHost.AddTab(spec); 

     spec = TabHost.NewTabSpec("sessions"); 
     spec.SetIndicator(this.GetText("Sessions"), Resources.GetDrawable(Resource.Drawable.Tab_Sessions)); 
     spec.SetContent(CreateIntentFor(ViewModel.Sessions)); 
     TabHost.AddTab(spec); 

     spec = TabHost.NewTabSpec("favorites"); 
     spec.SetIndicator(this.GetText("Favorites"), Resources.GetDrawable(Resource.Drawable.Tab_Favorites)); 
     spec.SetContent(CreateIntentFor(ViewModel.Favorites)); 
     TabHost.AddTab(spec); 

     spec = TabHost.NewTabSpec("tweets"); 
     spec.SetIndicator(this.GetText("Tweets"), Resources.GetDrawable(Resource.Drawable.Tab_Tweets)); 
     spec.SetContent(CreateIntentFor(ViewModel.Twitter)); 
     TabHost.AddTab(spec); 
    } 

, где соответствующий верхнего уровня ViewModel немного напоминает:

public class HomeViewModel 
    : MvxBaseViewModel 
{ 
    public HomeViewModel() 
    { 
     Welcome = new WelcomeViewModel(); 
     Sessions = new SessionsViewModel();    
     Twitter = new TwitterViewModel(); 
     Favorites = new FavoritesViewModel(); 
    } 

    public FavoritesViewModel Favorites { get; private set; } 
    public WelcomeViewModel Welcome { get; private set; } 
    public SessionsViewModel Sessions { get; private set; } 
    public TwitterViewModel Twitter { get; private set; } 
} 

...

В качестве варианта этой второй альтернативы (и это похоже на то, что вы пытаетесь сделать в этом вопросе), если ваша отдельная вкладка ViewModel не имеет отношения друг к другу или к родительскому элементу TabHost ViewModel , то вы можете связать каждую вкладку с новой ViewModel, созданной по требованию. Я не думаю, что какой-либо из общественных образцов сделать это, но если вам это нужно, то формат для этого будет:

 spec = TabHost.NewTabSpec("newTab"); 
     spec.SetIndicator("new tab text"), Resources.GetDrawable(Resource.Drawable.Tab_Icon)); 
     spec.SetContent(CreateIntentFor<NewViewModel>(new { constructorParameter1 = "value1", constructorParameter2 = "value2" })); 
     TabHost.AddTab(spec); 

Обратите внимание, что есть основная философия здесь происходит - это часть MvvmCross-х мнение - навигация/связь в mvx всегда о ViewModels, никогда не о представлениях. Идея состоит в том, что приложения создаются ViewModel-first - каждая клиентская платформа просто решает, как представлять эти ViewModels на экране. Это, скорее всего, будет продолжаться и развиваться еще дальше в разработке iPad и WinRT, где будут распространены функции splitviews, popups и т. Д.

Еще одно примечание. Если у вас есть сложная конструкция ViewModel или вам нужно использовать специальные сроки жизни для некоторых ваших ViewModels (например, одиночные игры), тогда также возможно использовать пользовательские ViewModelLocators в вашем «основном приложении» - они затем позволят вам изменять/управлять созданием динамического представления ViewModel, если вы хотите ... но я подозреваю, что это не так для этого вопроса.


Спасибо за деталь в вашем вопросе - извините за то, что выбрали расширенные параметры. Я постараюсь улучшить этот ответ с чуть более подробным объяснением позже сегодня или в эти выходные.


MVX также по-прежнему открыт для идей ... чтобы мы могли изменить код, чтобы работать с вами исходным кодом ... это будет не так трудно сделать, и я вижу какое-то оправдание для него. .. Я подумаю об этом ...

+0

Фантастический. Это было так же просто, как использование CreateIntentFor . Я использовал ViewModels для страниц вкладок, которые вернули временную строку, чтобы доказать, что они ленивы загружены - что они и были. Тем не менее, время не обновляется, когда я переключаюсь между вкладками (т. Е. Bindiung не повторится, когда вы переходите на вкладку). Как вы думаете, лучший способ справиться с этим? Еще раз спасибо! –

+0

Это другой вопрос - и это обычный mvvm! – Stuart

+0

Stackoverflow делает меня ленивым! :( Чтобы ответить себе на пользу другим, я добавил метод Refresh() в мой ViewModel и вызвал его из OnResume() в представлении, чтобы он вызывался каждый раз, когда просматривается вкладка. Обновляет обновления свойств ViewModel, которые также нужно вызвать FirePropertyChanged(). –

 Смежные вопросы

  • Нет связанных вопросов^_^