2011-05-15 191 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