2011-05-15 152 views
3

我试图让我的第一个Silverlight应用程序有史以来,但我不能让LogOn函数工作,你能帮我吗?这对你们来说应该是非常简单的,我会告诉你我的两个文件:LogOn.xaml.cs和LogOnViewModel.cs非常非常简单的MVVM问题

显然问题在于UserId的设置不够早,无法在LogOn.xaml中使用.CX我需要的时候,你能不能帮我做它的工作,这将提升我的时刻了不少:-)

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

回答

4

问题的原因是@flq强调的。你正在调用异步,这意味着你不会立即得到预期的结果(在你的情况下,UserId被分配),但是你可以指向Completed事件(或提供回调)到处理异步任务完成时的事情。

现在,“MVVM方式”做到这一点(或者至少我会做什么)如下:首先,去获得MVVM Light!这是一个轻量级的MVVM框架,这将是非常有用的。你应该让你的ViewModel类实现MVVMLight中的ViewModelBase基类,这将提供更改通知和消息以及其他有用的东西。然后,您应该将登录功能封装在一个命令中,以便能够从xaml连接它,因为您可以使用MVVMLight的RelayCommand。登录完成后,您可以发送消息到您的视图中,让它知道(以非常分离的方式),并且视图可以简单地启动导航。

这里的代码位为:

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

的XAML:

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

你可以看到,有一点点:

<TextBox Text="{Binding Username, Mode=TwoWay}"/> 
<TextBox Text="{Binding Password, Mode=TwoWay}"/> 
<Button Command="{Binding LoginCommand}"/> 
<TextBlock Text="{Binding LoginErrorMessage}"/>  
在后面的代码

ViewModel中的代码更多(但直接),而代码更少。这也利用了MVVM中心的DataBinding。

希望这有助于:)

PS:的LoginCompletedMessage类只是在这种情况下的空类(只用于定义类型的消息),但你可以用它来发送更多信息(也许你还想要用户ID发送)

+0

嗨Abdou Moumen,非常感谢您的所有工作,我只需要一段时间来看看它是否可以实现它的工作。我真的很失落和沮丧,但也许在查看你的代码并获得MVVMLight之后,我可以开始工作,我希望如此,以后我会回来的。 – rune007 2011-05-15 18:45:56

+0

@ rune007 silverlight是一个伟大的技术,MVVM是一个非常有趣的模式,所以保持它,祝你好运) – AbdouMoumen 2011-05-15 19:44:29

+0

再次感谢您的详细答案Abdou Moumen先生,您的文章是有用的,因为我了解MVVM和MVVMLight: - ) – rune007 2011-05-16 07:42:32

1

好吧,你调用一个登录WS.UserLoginAsync,这意味着一个异步版本执行继续进行,并且在您检查时确实没有用户标识。

你在这里并不是真的在做MVVVM,但无论如何,让我们来看看流程。在登录过程完成时在您的“Viewmodel”上发生事件(WS_UserLoginCompleted)。您可以处理它并在该事件的事件处理程序中触发导航。

+0

嗨flq非常感谢你的回应,我只是想知道我的代码可以改变只是为了实际做这个MVVM的东西,这是我第一次尝试了这一点,并且我应该正确地尝试做到正确,否则当我继续前进时,我的应用程序将最终变成一团糟。再次感谢您的回复:-) – rune007 2011-05-15 17:41:53