C# Xamarin形成对所有viewmodels的访问权限

C# Xamarin形成对所有viewmodels的访问权限,c#,xaml,mvvm,xamarin,xamarin.forms,C#,Xaml,Mvvm,Xamarin,Xamarin.forms,我在项目中使用ViewModelLocator 我在app.xaml中绑定ResourceDictionary中ViewModelLocator的内容 我的代码: App.xaml <?xml version="1.0" encoding="utf-8" ?> <Application xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/

我在项目中使用ViewModelLocator

我在app.xaml中绑定ResourceDictionary中ViewModelLocator的内容

我的代码:

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

}
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


               });
           }
        }
}
注册ViewModel.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();
            }
        }

}
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获取数据

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

我怎么做

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

我将BindingContext添加到app.xaml中

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

这是一个好的做法吗?

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

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

最明显的(也是最糟糕的)方法是在SignupViewModel中获取对LoginViewModel的引用,并直接引用其属性。不幸的是,这是一个非常脆弱的解决方案,并且强制执行对LoginView模型的硬依赖。如果您的登录流发生更改,则您的SignupViewModel必须随之更改。不理想

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

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

参数传递可能是最轻量级的解决方案,但不幸的是,Xamarin表单不支持这种开箱即用的解决方案。我以前实现过它,但它涉及一些工作

允许您订阅和发布任意消息的消息传递系统是一种非常常见的解决方案(事实上,事件实际上是这种解决方案的一种特定形式)。如果您正在寻找一个快速加入的解决方案,我认为这可能是您最好的选择,因为随附的Messenger正是这样做的。即使您不使用确切的实现,但从根本上说,您也希望执行以下操作:

public interface IMessenger
{
    Publish<TMessage>(TMessage);
    Subscribe<TMessage>(object, Action<TMessage>); //the object here should be a reference to the recipient.
}
假设您的Messenger实现了某种界面,如下所示:

public interface IMessenger
{
    Publish<TMessage>(TMessage);
    Subscribe<TMessage>(object, Action<TMessage>); //the object here should be a reference to the recipient.
}
您的登录视图模型:

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
    }
}
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
    }
}
公共类LoginViewModel:AbstractViewModel { //你所有的财产都在这里。。。 伊梅森格信使参考; 公共登录视图模型() { //以某种方式获取对Messenger的引用。可能是ViewModelLocator中的单例? Messenger参考=ViewModelLocator.Messenger; } //当您离开LoginViewModel时,或者将此信息发送到您的SignupViewModel时,可能会调用此方法。 私有无效密码信息() { messagereference.Publish(新登录消息{Username=this.Username});//等 } } 您的注册视图模型:

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
    }
}
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
    }
}
公共类注册视图模型:AbstractViewModel
{
//你所有的财产都在这里。。。
公共注册视图模型()
{
//以某种方式获取对Messenger的引用。可能是ViewModelLocator中的单例?
IMessenger Messenger引用=ViewModelLocator.Messenger;
messenger.Register(此,仅登录MessageReceived);
}
private OnLoginMessageReceived(LoginMessageGeargs消息)
{
//用你的信息做一些事情
}
}

唷!希望这会有所帮助。

为注册视图模型添加代码也添加登录视图模型。@santoshkumar请检查答案,在xamarin中执行相同的操作,您会得到答案。要回答您的问题,请阅读上面PingZing中的答案