非常非常简单的MVVM问题
我试图让我的第一个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));
}
}
}
问题的原因是@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发送)
好吧,你调用一个登录WS.UserLoginAsync
,这意味着一个异步版本执行继续进行,并且在您检查时确实没有用户标识。
你在这里并不是真的在做MVVVM,但无论如何,让我们来看看流程。在登录过程完成时在您的“Viewmodel”上发生事件(WS_UserLoginCompleted
)。您可以处理它并在该事件的事件处理程序中触发导航。
嗨flq非常感谢你的回应,我只是想知道我的代码可以改变只是为了实际做这个MVVM的东西,这是我第一次尝试了这一点,并且我应该正确地尝试做到正确,否则当我继续前进时,我的应用程序将最终变成一团糟。再次感谢您的回复:-) – rune007 2011-05-15 17:41:53
嗨Abdou Moumen,非常感谢您的所有工作,我只需要一段时间来看看它是否可以实现它的工作。我真的很失落和沮丧,但也许在查看你的代码并获得MVVMLight之后,我可以开始工作,我希望如此,以后我会回来的。 – rune007 2011-05-15 18:45:56
@ rune007 silverlight是一个伟大的技术,MVVM是一个非常有趣的模式,所以保持它,祝你好运) – AbdouMoumen 2011-05-15 19:44:29
再次感谢您的详细答案Abdou Moumen先生,您的文章是有用的,因为我了解MVVM和MVVMLight: - ) – rune007 2011-05-16 07:42:32