[英]Xamarin Forms access to all viewmodels
我在项目中使用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获取数据。
我该怎么做?
您的问题比我想象的要微妙和复杂。
您在问“如何从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
}
}
呼! 希望有帮助。
我找到了解决问题的方法。 但是我不确定这是个好方法。
我将BindingContext添加到app.xaml
<Application.BindingContext>
<x:StaticResource Key="ViewModelLocator"/>
</Application.BindingContext>
我可以访问ViewModelLocator和LoginViewModel。
var model=Application.Current.BindingContext as ViewModelLocator;
var login=model?.LoginViewModel.UserName;
这是好习惯吗?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.