c# - Xamarin 在 PushAsync() 之前初始化 ViewModel
问题描述
我有一个带有登录页面的 Xamarin 应用程序,我使用 ServiceContainer 注册了我的数据库、警报、媒体和导航服务。然后我尝试导航到登录页面,但在它出现在屏幕上之前,它会为每个 ViewModel 调用构造函数,我不知道为什么???
public partial class App : Application
{
INavigationService NavigationService { get; set; }
public App()
{
InitializeComponent();
RegisterRepositories();
RegisterServices();
NavigationService.ReplaceRoot(ServiceContainer.GetInstance<LoginViewModel>(), false);
}
void RegisterServices()
{
ServiceContainer.Register<IAlertService>(() => new AlertService());
ServiceContainer.Register<IMediaService>(() => new MediaService());
NavigationService = new NavigationService();
NavigationService.AutoRegister(typeof(App).Assembly);
ServiceContainer.Register(NavigationService);
}
void RegisterRepositories()
{
ServiceContainer.Register<IUserProfileRepository>(() => new UserProfileRepository());
}
服务容器:
public static class ServiceContainer
{
static readonly Container _container = new Container();
public static void Register<TService, TImplementation>(bool transient = false) where TService : class where TImplementation : class, TService
{
Lifestyle style = transient ? Lifestyle.Transient : Lifestyle.Singleton;
_container.Register<TService, TImplementation>(style);
}
public static void Register<TService>(Func<TService> generator, bool transient = false) where TService : class
{
Lifestyle style = transient ? Lifestyle.Transient : Lifestyle.Singleton;
_container.Register(generator, style);
}
public static void Register(Type serviceType, Type implementationType, bool isTransient = false)
{
if (isTransient)
{
_container.Register(serviceType, implementationType, Lifestyle.Transient);
}
else
{
_container.Register(serviceType, implementationType, Lifestyle.Singleton);
}
}
public static void Register<TService>(TService instance) where TService : class
{
_container.RegisterInstance(instance);
}
public static T GetInstance<T>() where T : class
{
try
{
return _container.GetInstance<T>();
}
catch (ActivationException)
{
return null;
}
}
internal static T GetRequiredInstance<T>() where T : class
{
return GetInstance<T>() ?? throw new InvalidOperationException(
$@"A required dependency injection class is missing ({typeof(T).FullName}).");
}
}
导航服务:
public interface IViewFor
{
object ViewModel { get; set; }
}
public interface IViewFor<T> : IViewFor where T : BaseViewModel
{
new T ViewModel { get; set; }
}
public class NavigationService : INavigationService
{
INavigation FormsNavigation => Application.Current.MainPage.Navigation;
readonly Dictionary<Type, Type> _viewModelViewDictionary = new Dictionary<Type, Type>();
public void AutoRegister(Assembly asm)
{
// Loop through everything in the assembly that implements IViewFor<T>
foreach (var type in asm.DefinedTypes.Where(dt => !dt.IsAbstract &&
dt.ImplementedInterfaces.Any(ii => ii == typeof(IViewFor))))
{
// Get the IViewFor<T> portion of the type that implements it
var viewForType = type.ImplementedInterfaces.FirstOrDefault(
ii => ii.IsConstructedGenericType &&
ii.GetGenericTypeDefinition() == typeof(IViewFor<>));
// Register it, using the T as the key and the view as the value
Register(viewForType.GenericTypeArguments[0], type.AsType());
ServiceContainer.Register(viewForType.GenericTypeArguments[0], viewForType.GenericTypeArguments[0], true);
}
}
public void Register(Type viewModelType, Type viewType)
{
if (!_viewModelViewDictionary.ContainsKey(viewModelType))
{
_viewModelViewDictionary.Add(viewModelType, viewType);
}
}
public void ReplaceRoot<T>(bool withNavigationEnabled = true) where T : BaseViewModel
{
ReplaceRoot(ServiceContainer.GetInstance<T>(), withNavigationEnabled);
}
public void ReplaceRoot(BaseViewModel viewModel, bool withNavigationEnabled = true)
{
if (InstantiateView(viewModel) is Page view)
{
if (withNavigationEnabled)
{
Application.Current.MainPage = new NavigationPage(view);
}
else
{
Application.Current.MainPage = view;
}
}
}
public Task PopAsync() => FormsNavigation.PopAsync(true);
public Task PopToRootAsync(bool animate) => FormsNavigation.PopToRootAsync(animate);
public Task PushAsync(BaseViewModel viewModel) => FormsNavigation.PushAsync((Page)InstantiateView(viewModel));
IViewFor InstantiateView(BaseViewModel viewModel)
{
var viewModelType = viewModel.GetType();
var viewType = _viewModelViewDictionary[viewModelType];
var view = (IViewFor)Activator.CreateInstance(viewType);
view.ViewModel = viewModel;
return view;
}
}
解决方案
推荐阅读
- c++ - 在 openCL 2.0 中使用 enqueueFillBuffer 会产生垃圾
- python-3.x - 每当我尝试通过烧瓶连接我的 psql 时,我都会收到一个 contrib 错误
- javascript - 是否可以从服务工作者文件运行 socketIO 连接
- django - 具有多个 url 参数的 django-rest
- flutter - 我想放置一个自定义小部件来代替 appbar,并希望在它下面有一个标签视图
- javascript - 如何将索引号传递给反应类?
- python - 一些 Keras 预训练的网络在使用之前是否需要特殊的预处理?
- c# - .NET Core - HTTPClient - Ubuntu 20.04 上的 dh 密钥太小
- c++ - 如何让“make”知道其他目录的变化?
- javascript - 使用变量值作为角度标签属性值