【问题标题】:Xamarin Forms access to all viewmodelsXamarin Forms 访问所有视图模型
【发布时间】:2017-05-18 10:27:27
【问题描述】:

我在我的项目中使用 ViewModelLocator。

我在 app.xaml 中的 ResourceDictionary 中执行 ViewModelLocator 的 BindingContent

我的代码:

App.xaml

<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:controlsHelpers="clr-namespace:MyProj.Source.Helpers.UIHelper.ControlsHelpers;assembly=MyProj"
             xmlns:configuration="clr-namespace:MyProj.Source.Configuration;assembly=MyProj"
             x:Class="MyProj.App">
  <Application.Resources>

    <ResourceDictionary>
      <configuration:ViewModelLocator x:Key="ViewModelLocator"/>
      </ResourceDictionary>
  </Application.Resources>
</Application>

ViewModelLocator.cs

 public class ViewModelLocator
 {
        public LoginViewModel LoginViewModel { get; set; }
        public SignUpViewModel SignUpViewModel { get; set; }


        public ViewModelLocator()
        {
            LoginViewModel = new LoginViewModel();
            SignUpViewModel = new SignUpViewModel();
        }
 }

LoginViewModel.cs

public class LoginViewModel : AbstractViewModel
{

        private MyModel UserData { get; set; } = new MyModel();


        private bool _isSignRequired;


        public bool IsSignRequired
        {
            get { return _isSignRequired; }
            set
            {
                if (value == _isSignRequired) return;
                _isSignRequired = value;
                OnPropertyChanged();
            }
        }

        public string UserName
        {
            get { return UserData.UserName; }
            set
            {
                if (value == UserData.UserName) return;
                UserData.UserName = value;
                OnPropertyChanged();
            }
        }

        public string Password
        {
            get { return UserData.Password; }
            set
            {
                if (value == UserData.Password) return;
                UserData.Password = value;
                OnPropertyChanged();
            }
        }

}

SignUpViewModel.cs

public class SignUpViewModel : AbstractViewModel
{    
        private string _checkUserResultImage;

        public MyModel UserData { get; set; } = new MyModel();

        public string Phone
        {
            get { return UserData.Phone; }
            set
            {
                if (UserData.Phone != null && value == UserData.Phone) return;
                UserData.Phone = value;
                OnPropertyChanged();
            }
        }

        public string UserName
        {
            get { return UserData.UserName; }
            set
            {
                if (UserData.UserName != null && value == UserData.UserName) return;
                UserData.UserName = value;
                OnPropertyChanged();
            }
        }

        public string Password
        {
            get { return UserData.Password; }
            set
            {
                if (UserData.Password != null && value == UserData.Password) return;
                UserData.Password = value;
                OnPropertyChanged();
            }
        }

        public string Email
        {
            get { return UserData.Email; }

            set
            {
                if (UserData.Email != null && value == UserData.Email) return;
                UserData.Email = value;
                OnPropertyChanged();
            }
        }

        public string CheckUserResultImage
        {
            get { return _checkUserResultImage; }
            set
            {
                if (value == _checkUserResultImage) return;
                _checkUserResultImage = value;
                    OnPropertyChanged();
            }
        }


        public Command SignUpCommand
        {
           get
           {
               return new Command(async () =>
               {
                   //Here I want to get data field from LoginViewModel


               });
           }
        }
}

我想从 SignUpViewModel 中的 LoginViewModel 获取数据。

我该怎么做?

【问题讨论】:

  • 为 SignUpViewModel 添加代码
  • 也添加 LoginViewModel。
  • @santoshkumar 完成
  • 请检查答案在 xamarin 中执行相同的操作,您将得到它。

标签: c# xaml mvvm xamarin xamarin.forms


【解决方案1】:

您的问题比我认为您可能意识到的要微妙和复杂一些。

您在问“如何从我的 LoginViewModel 获取信息到我的 SignupViewModel?”有很多不同的方法可以做到这一点!不幸的是,它们中的许多都很糟糕,并且违背了 MVVM 设计模式的目的。 MVVM 鼓励组件解耦和封装。

最明显(也是最糟糕)的方法是简单地在 SignupViewModel 中获取对 LoginViewModel 的引用,并直接引用它的属性。不幸的是,这是一个非常脆弱的解决方案,并且强制依赖于您的 LoginViewModel。如果您的登录流程发生变化,您的 SignupViewModel 必须随之更改。不理想。

因此,为了避免组件的紧密耦合,您需要做一些更简单的事情:只传递您感兴趣的数据。也有很多方法可以做到这一点,例如事件、参数传递或消息系统。

事件可以正常工作,但我建议不要使用它们,因为它再次迫使您的 SignupViewModel 直接依赖于您的 LoginViewModel。如果你对此没问题,它可以工作。

参数传递可能是最轻量级的解决方案,但不幸的是,Xamarin Forms 不支持此功能。我以前实现过,但它涉及一些工作。

允许您订阅和发布任意消息的消息传递系统是一种非常常见的解决方案(事实上,事件实际上是这种方式的一种特定形式)。如果您正在寻找一个快速的解决方案,我认为这可能是您最好的选择,因为MVVM Light Toolkit 带有一个可以做到这一点的 Messenger。即使你不使用那个确切的实现,但从根本上说,你会想要做这样的事情:

假设您的 Messenger 实现了某种如下所示的接口:

public interface IMessenger
{
    Publish<TMessage>(TMessage);
    Subscribe<TMessage>(object, Action<TMessage>); //the object here should be a reference to the recipient.
}

然后你的实现可能看起来像这样:

你会使用这个类来传递信息:

public class LoginMessageArgs
{
    public string Username {get; private set;}
    //whatever other information this message needs to contain...         
}

您的 LoginViewModel:

public class LoginViewModel : AbstractViewModel
{
    //all your properties go here...

    IMessenger messengerReference;

    public LoginViewModel()
    {
        //Get a reference to your Messenger somehow. Maybe it's a singleton in ViewModelLocator?
        messengerReference = ViewModelLocator.Messenger;
    }

     //Maybe you call this method when you navigate away from the LoginViewModel, or whenever it makes sense to send this information to your SignupViewModel.
    private void PassLoginInformation()
    {
        messengerReference.Publish<LoginMessageArgs>(new LoginMessageArgs { Username = this.Username }); //etc
    }
}

您的 SignupViewModel:

public class SignUpViewModel : AbstractViewModel
{

    //all your properties go here...

    public SignupViewModel()
    {
        //Get a reference to your Messenger somehow. Maybe it's a singleton in ViewModelLocator?
        IMessenger messengerReference = ViewModelLocator.Messenger;
        messenger.Register<LoginMessageArgs>(this, OnLoginMessageReceived);
    }

    private OnLoginMessageReceived(LoginMessageArgs message)
    {
        //Do stuff with your message
    }
}

哇!希望这会有所帮助。

【讨论】:

    【解决方案2】:

    我找到了解决我的问题的解决方案。但我不确定这是个好方法。

    我在 app.xaml 中添加了 BindingContext

     <Application.BindingContext>
        <x:StaticResource Key="ViewModelLocator"/>
      </Application.BindingContext>
    

    我可以访问 ViewModelLocator 和 LoginViewModel。

    var model=Application.Current.BindingContext as ViewModelLocator;
    var login=model?.LoginViewModel.UserName;
    

    这是好的做法吗?

    【讨论】:

    • 回答您的问题 - 从 PingZing 阅读上述答案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-20
    • 2017-04-08
    • 2021-07-28
    • 1970-01-01
    • 1970-01-01
    • 2020-05-23
    • 2017-04-25
    相关资源
    最近更新 更多