2017-04-06 1 views
1

Je travaille sur l'application multiplateforme xamarin.form, je veux naviguer d'une page à l'autre en cliquant sur le bouton. Comme je ne peux pas faire Navigation.PushAsync(new Page2()); dans ViewModel parce que c'est seulement possible dans le fichier Code-Behid. S'il vous plaît suggérer un moyen de le faire?Xamarin.form Page Navigation dans mvvm

Voici mon avis:

<?xml version="1.0" encoding="utf-8" ?> 
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
      xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
      x:Class="Calculator.Views.SignIn" 
      xmlns:ViewModels="clr-namespace:Calculator.ViewModels;assembly=Calculator"> 

    <ContentPage.BindingContext> 
     <ViewModels:LocalAccountViewModel/> 
    </ContentPage.BindingContext> 

    <ContentPage.Content> 

      <StackLayout> 
       <Button Command="{Binding ContinueBtnClicked}"></Button> 

      </StackLayout> 


    </ContentPage.Content> 
</ContentPage> 

Voici mon ViewModel:

public class LocalAccountViewModel : INotifyPropertyChanged 
     { 




      public LocalAccountViewModel() 
      { 
       this.ContinueBtnClicked = new Command(GotoPage2); 
      } 


      public void GotoPage2() 
      { 
       ///// 

      } 


      public ICommand ContinueBtnClicked 
      { 

       protected set; 
       get; 
      } 

      public event PropertyChangedEventHandler PropertyChanged; 


     protected virtual void OnPropertyChanges([CallerMemberName] string PropertyName = null) 
     { 
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName)); 
     } 

     } 
+0

vous pouvez essayer freshmvvm, il est assez facile à comprendre fonctionne comme un charme – batmaci

Répondre

2

Une façon est que vous pouvez passer la navigation dans la machine virtuelle Constructeur. Comme les pages héritent de VisualElement, elles héritent directement de la propriété Navigation.

fichier code-behind:

public class SignIn : ContentPage 
{ 
    public SignIn(){ 
     InitializeComponent(); 
     // Note the VM constructor takes now a INavigation parameter 
     BindingContext = new LocalAccountViewModel(Navigation); 
    } 
} 

Puis dans votre machine virtuelle, ajoutez une propriété INavigation et changer le constructeur d'accepter un INavigation. Vous pouvez ensuite utiliser cette propriété pour la navigation:

public class LocalAccountViewModel : INotifyPropertyChanged 
{ 

     public INavigation Navigation { get; set;} 


     public LocalAccountViewModel(INavigation navigation) 
     { 
      this.Navigation = navigation; 
      this.ContinueBtnClicked = new Command(async() => await GotoPage2()); 
     } 


     public async Task GotoPage2() 
     { 
      ///// 
      await Navigation.PushAsync(new Page2()); 
     } 


     ... 

Remarque un problème avec votre code que vous devez fixer: La méthode GoToPage2() doit être async et renvoyer le type Task. En outre, la commande effectuera un appel d'action asynchrone. C'est parce que vous devez faire la navigation de la page de manière asynchrone!

J'espère que ça aide!

+0

Cela fonctionne mais si nous voulons Bind Context dans le fichier de vue Xaml. comment pouvons-nous passer paramètre pour voir le constructeur du modèle? et quel est le meilleur moyen de lier le contexte dans Code Behid File ou dans Xaml? –

+0

@WaleedArshad: Le 'DataContext' est créé après l'appel' InitializeComponent() '. Vous pouvez donc simplement le passer au ViewModel par la suite. Je règle généralement le ViewModel dans le constructeur au cas où il aurait besoin de paramètres supplémentaires (c'est le seul code que j'essaie de mettre dans le code). Je trouve aussi plus facile à lire. Si vous n'avez pas de paramètres, c'est une question de choix. –

+0

Je suis désolé de me lancer - mais cela casse complètement toutes les règles MVVM/MVC/MVWhatever .... Votre ViewModel ne devrait jamais créer une vue - c'est l'inverse. Le but de tous ces concepts est de séparer la vue du modèle, de sorte que la vue est interchangeable, ce qui n'est pas le cas dans votre exemple. Imaginez juste faire des projets séparés (vrais * .csproj-fichiers) pour View, ViewModel et Model et vous verrez le problème. Venant de l'histoire de WPF, je suis venu ici en regardant comment les gars de Xamarin font ça et jusqu'à maintenant je ne suis pas vraiment content des concepts que j'ai trouvés ... Je continuerai à chercher! –

9

Une façon simple est

this.ContinueBtnClicked = new Command(async()=>{ 

    await Application.Current.MainPage.Navigation.PushAsync(new Page2()); 
}); 
+0

Cela a également fonctionné. et c'est un moyen très simple de naviguer vers une autre page. –

0

J'ai regardé cela, et cela dépend vraiment de la façon dont vous voulez gérer votre navigation. Voulez-vous que vos modèles de vue gèrent votre navigation ou que vous souhaitiez obtenir vos vues? J'ai trouvé plus facile d'avoir mes vues gérer ma navigation afin que je puisse choisir d'avoir un format de navigation différent pour différentes situations ou applications. Dans cette situation, plutôt que d'utiliser le modèle de liaison de commandes, utilisez simplement un événement cliqué sur un bouton et ajoutez la nouvelle page à la pile de navigation dans le code qui suit.

Changez votre bouton pour quelque chose comme:

<StackLayout> 
    <Button Clicked="Button_Clicked"></Button> 
</StackLayout> 

Et dans votre code derrière, mettre en œuvre la méthode et y faire la navigation.

public void Button_Clicked(object sender, EventArgs e) 
{ 
    Navigation.PushAsync(new Page2()); 
} 

Si vous cherchez à faire la navigation à base de viewmodel, je crois qu'il ya une façon de le faire avec MvvmCross, mais je ne suis pas familier avec cet outil.

2

À partir de votre machine virtuelle

public Command RegisterCommand 
     { 
      get 
      { 
       return new Command(async() => 
       { 
        await Application.Current.MainPage.Navigation.PushAsync(new RegisterNewUser()); 
       }); 

      } 
     } 
0

mon approche basée sur le principe chaque modèle peut naviguer dans des endroits en fonction du contexte VM de l'application seulement:

En ViewModel je déclare interfeces INavigationHandler comme ça:

public class ItemsViewModel : ViewModelBase 
{ 
    public INavigationHandler NavigationHandler { private get; set; } 


    // some VM code here where in some place i'm invoking 
    RelayCommand<int> ItemSelectedCommand => 
     new RelayCommand<int>((itemID) => { NavigationHandler.NavigateToItemDetail(itemID); }); 


    public interface INavigationHandler 
    { 
     void NavigateToItemDetail(int itemID); 
    } 
} 

Et affecter une classe de code-behind comme INavigationHandler pour ViewModel:

public class ItemsPage : ContentPage, ItemsViewModel.INavigationHandler 
{ 
    ItemsViewModel viewModel; 

    public ItemsPage() 
    { 
     viewModel = Container.Default.Get<ItemsViewModel>(); 
     viewModel.NavigationHandler = this; 
    } 


    public async void NavigateToItemDetail(int itemID) 
    { 
     await Navigation.PushAsync(new ItemDetailPage(itemID)); 
    } 
}