【问题标题】:Very very simple MVVM problem非常非常简单的 MVVM 问题
【发布时间】:2011-08-25 23:35:21
【问题描述】:

我正在尝试制作我的第一个 Silverlight 应用程序,但我无法使用 LogOn 功能,您能帮帮我吗?这对你们来说应该非常简单,我将向你们展示我的两个文件:LogOn.xaml.cs 和 LogOnViewModel.cs

显然,问题是 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));
        }
    }
}

【问题讨论】:

    标签: c# silverlight windows-phone-7 mvvm


    【解决方案1】:

    问题的原因是@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:

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

    在后面的代码中:

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

    您可以看到 ViewModel 中的代码多一点(但直截了当),而后面的代码则少一些。这也利用了 MVVM 核心的 DataBinding。

    希望这会有所帮助:)

    PS: LoginCompletedMessage 类在这种情况下只是一个空类(仅用于定义消息类型),但您可以使用它来发送更多信息(也许您仍然希望拥有已发送用户 ID)

    【讨论】:

    • 您好 Abdou Moumen,非常感谢您所做的所有工作,我需要一些时间来看看它是否可以正常工作。我真的很失落和沮丧,但也许在看了你的代码并得到 MVVMLight 之后我可以让它工作,我希望如此,我稍后会回来。
    • @rune007 silverlight 是一项伟大的技术,而 MVVM 是一个非常有趣的模式,所以继续努力吧,祝你好运 ;)
    • 再次感谢 Abdou Moumen 先生的精心回答,您的帖子对我了解 MVVM 和 MVVMLight 很有帮助:-)
    【解决方案2】:

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

    您实际上并没有在这里执行 MVVVM,但无论如何,让我们顺其自然。在您的“Viewmodel”上发生一个在登录过程完成时引发的事件 (WS_UserLoginCompleted)。您可以处理它并在该事件的事件处理程序中触发导航。

    【讨论】:

    • 您好 flq 非常感谢您的回复,我只是想知道我的代码是否可以简单地更改为实际执行此 MVVM 的东西,这是我第一次尝试这个,我应该正确试着把它做对,否则当我继续前进时,我的应用程序将最终变成一团糟。再次感谢您的回复:-)
    猜你喜欢
    • 2011-10-28
    • 1970-01-01
    • 2016-03-12
    • 2011-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多