2011-05-15 5 views
3

J'essaie de faire ma toute première application Silverlight, mais je n'arrive pas à faire fonctionner la fonction LogOn, pouvez-vous m'aider? Cela devrait être vraiment super simple pour vous tous, je vais vous montrer mes deux fichiers: LogOn.xaml.cs et LogOnViewModel.csProblème MVVM très très simple

Apparemment, le problème est que UserId n'est pas réglé assez tôt pour être disponible dans LogOn.xaml .cx quand j'ai besoin, pouvez-vous me aider à le faire fonctionner, qui lèverait mon moment un peu :-)

public partial class LogOn : PhoneApplicationPage 
{ 
    public LogOn() 
    { 
     InitializeComponent(); 
     this.DataContext = LogOnViewModel.Instance; 
    } 

    private void btnLogOn_Click(object sender, RoutedEventArgs e) 
    { 
     if ((!string.IsNullOrEmpty(txtEmailAddress.Text)) && (!string.IsNullOrEmpty(txtPassword.Password))) 
     { 
      txbLogonMessage.Text = ""; 
      LogOnViewModel.Instance.UserLogin(txtEmailAddress.Text, txtPassword.Password); 

      if (LogOnViewModel.Instance.UserId > 0) 
       NavigationService.Navigate(new Uri("/_2HandApp;component/Views/Main.xaml", UriKind.Relative)); 
      else 
       txbLogonMessage.Text = "Login was unsuccessful. The user name or password provided is incorrect. Please correct the errors and try again. "; 
     } 
    } 
} 


public sealed class LogOnViewModel : INotifyPropertyChanged 
{ 
    public static LogOnViewModel Instance = new LogOnViewModel(); 
    //public static int userId; 

    private SHAServiceClient WS; 

private int userId; 
    public int UserId 
    { 
     get 
     { 
      return userId; 
     } 

     set 
     { 
      userId = value; 
      this.RaisePropertyChanged("UserId"); 
     } 
    } 


private LogOnViewModel() 
    { 
     WS = new SHAServiceClient(); 
     WS.UserLoginCompleted += new EventHandler<UserLoginCompletedEventArgs>(WS_UserLoginCompleted); 
    } 

    void WS_UserLoginCompleted(object sender, UserLoginCompletedEventArgs e) 
    { 
     if (e.Error == null) 
     { 
      this.UserId = e.Result; 
     } 
    } 


    public void UserLogin(string email, string password) 
    { 
     WS.UserLoginAsync(email, password); 
    } 

/* Implementing the INotifyPropertyChanged interface. */ 
    public event PropertyChangedEventHandler PropertyChanged; 
    private void RaisePropertyChanged(string propertyName) 
    { 
     PropertyChangedEventHandler propertyChanged = this.PropertyChanged; 
     if ((propertyChanged != null)) 
     { 
      propertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

Répondre

4

La cause du problème est ce qui a été mis en évidence par @flq. Vous effectuez un appel asynchrone, ce qui signifie que vous n'obtiendrez pas le résultat attendu immédiatement (dans votre cas, l'ID utilisateur étant affecté), mais à la place, vous pouvez vous abonner à l'événement Completed (ou fournir un rappel) à gérer les choses lorsque la tâche asynchrone se termine. Maintenant, la "voie MVVM" pour faire ceci (ou du moins ce que je ferais) est la suivante: tout d'abord, allez chercher MVVM Light! c'est un framework MVVM léger qui serait très utile. Votre classe ViewModel devrait implémenter la classe de base ViewModelBase de MVVMLight, ceci fournirait la notification de changement et la messagerie ainsi que d'autres choses utiles. Ensuite, vous devriez encapsuler la fonctionnalité de connexion dans une commande pour pouvoir la relier à partir de xaml, pour cela vous pouvez utiliser de MVVMLight. Une fois la connexion terminée, vous pouvez simplement envoyer un message à votre avis en le faisant savoir (d'une manière assez découplée), et la vue peut simplement lancer la navigation.

est ici les bits de code pour que:

public class LogOnViewModel : ViewModelBase 
{ 
    private SHAServiceClient WS; 
    public LogOnViewModel() 
    { 
     WS = new SHAServiceClient(); 
     WS.UserLoginCompleted += new EventHandler<UserLoginCompletedEventArgs>(WS_UserLoginCompleted); 
     LoginCommand = new RelayCommand(UserLogin); 
    } 
    private int userId; 
    public int UserId 
    { 
     get { return userId; } 
     set 
     { 
      userId = value; 
      RaisePropertyChanged(()=>UserId); 
     } 
    } 
    private int password; 
    public int Password 
    { 
     get { return password; } 
     set 
     { 
      password = value; 
      RaisePropertyChanged(()=>Password); 
     } 
    } 
    private int username; 
    public int Username 
    { 
     get { return username; } 
     set 
     { 
      username = value; 
      RaisePropertyChanged(()=>Username); 
     } 
    } 
    private int loginErrorMessage; 
    public int LoginErrorMessage 
    { 
     get { return loginErrorMessage; } 
     set 
     { 
      loginErrorMessage = value; 
      RaisePropertyChanged(()=>LoginErrorMessage); 
     } 
    } 
    void WS_UserLoginCompleted(object sender, UserLoginCompletedEventArgs e) 
    { 
     if (e.Error == null) 
     { 
      this.UserId = e.Result; 
      // send a message to indicate that the login operation has completed 
      Messenger.Default.Send(new LoginCompleteMessage()); 
     } 
    } 
    public RelayCommand LoginCommand {get; private set;} 
    void UserLogin() 
    { 
     WS.UserLoginAsync(email, password); 
    } 
} 

pour le XAML:

<TextBox Text="{Binding Username, Mode=TwoWay}"/> 
<TextBox Text="{Binding Password, Mode=TwoWay}"/> 
<Button Command="{Binding LoginCommand}"/> 
<TextBlock Text="{Binding LoginErrorMessage}"/>  

dans le code sous-jacent:

public partial class LogOn : PhoneApplicationPage 
{ 
    public LogOn() 
    { 
     InitializeComponent(); 
     this.DataContext = new LogOnViewModel(); 
     Messenger.Default.Register<LoginCompletedMessage>(
          this, 
          msg=> NavigationService.Navigate(
            new Uri("/_2HandApp;component/Views/Main.xaml", 
            UriKind.Relative)); 
    } 
    .... 
} 

Vous pouvez voir qu'il ya un peu peu plus (mais simple) code dans le ViewModel et moins dans le code derrière. Cela a également profité de DataBinding qui est au cœur de MVVM.

Hope this helps :)

PS: la classe LoginCompletedMessage est juste une classe vide dans ce cas (utilisé juste pour définir le message de type), mais vous pouvez l'utiliser pour envoyer plus d'information (peut-être vous veulent toujours avoir le UserId envoyé)

+0

Salut Abdou Moumen, merci beaucoup pour tout votre travail, je vais juste besoin de le regarder un jour pour voir si je peux le faire fonctionner.J'étais vraiment perdu et déprimé, mais peut-être qu'après avoir regardé votre code et obtenu MVVMLight je peux le faire fonctionner, je l'espère, je serai de retour plus tard. – rune007

+0

@ rune007 silverlight est une excellente technologie et MVVM est un modèle très intéressant, alors continuez et bonne chance;) – AbdouMoumen

+0

Encore une fois merci pour votre réponse élaborée M. Abdou Moumen, votre message est utile que j'apprends à propos de MVVM et MVVMLight: -) – rune007

1

Eh bien, vous appelez une version async d'une connexion WS.UserLoginAsync, ce qui signifie la l'exécution se poursuit et, en effet, il n'y a pas d'identifiant d'utilisateur lorsque vous vérifiez.

Vous ne faites pas vraiment MVVVM ici, mais de toute façon, allons-y avec le flux. Avoir un événement sur votre "Viewmodel" qui est levé lorsque le processus de connexion est terminé (WS_UserLoginCompleted). Vous pouvez le gérer et déclencher la navigation dans un gestionnaire d'événements de cet événement.

+0

Salut FLQ Merci beaucoup pour votre réponse, je me demandais ce que mon code soit modifié simplement en train de faire ce genre de choses MVVM, c'est ma première fois que je suis en train ceci, et Je devrais correctement essayer de le faire correctement sinon mon application finira comme un gâchis quand je passerai à autre chose. Encore merci pour votre réponse :-) – rune007