Kzr*_*tof 4 .net c# autofac uwp
我在UWP应用程序中使用autofac。在我的App实例中,我正在建立依赖关系,如下所示:
public sealed partial class App
{
private readonly IFacade m_facade;
public App()
{
InitializeComponent();
m_facade = InitializeDependencies();
Suspending += OnSuspending;
}
private IFacade InitializeDependencies()
{
var containerBuilder = new ContainerBuilder();
// Registers all the platform-specific implementations of services.
containerBuilder.RegisterType<LoggingService>()
.As<ILoggingService>()
.SingleInstance();
containerBuilder.RegisterType<SQLitePlatformService>()
.As<ISQLitePlatformService>()
.SingleInstance();
containerBuilder.RegisterType<DiskStorageService>()
.As<IDiskStorageService>()
.SingleInstance();
...
containerBuilder.RegisterType<Facade>()
.As<IFacade>();
// Auto-magically resolves the IFacade implementation.
var facadeContainer = containerBuilder.Build();
var facadeLifetimeScope = m_facadeContainer.BeginLifetimeScope();
return facadeLifetimeScope.Resolve<IFacade>();
}
}
Run Code Online (Sandbox Code Playgroud)
我需要将IFacade实例传递给不同Page的,以达到我的视图模型。这是我的其中一个页面的示例:
internal sealed partial class SomePage
{
public SomePageViewModel ViewModel { get; }
public SomePage()
{
ViewModel = new SomePageViewModel(/* need an IFacade implementation here!! */);
InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
ViewModel.LoadAsync();
base.OnNavigatedTo(e);
}
}
Run Code Online (Sandbox Code Playgroud)
UWP负责Page实例化,因此它限制了我的选择。这是在UWP中完成从一页到另一页的导航的方法。从App实例:
rootFrame.Navigate(typeof(MainPage), e.Arguments);
Run Code Online (Sandbox Code Playgroud)
或从Page实例:
ContentFrame.Navigate(typeof(SomeOtherPage));
Run Code Online (Sandbox Code Playgroud)
题
将我的IFacade实例传递给视图模型的正确方法是什么(显然不做任何棘手的事情)?
由于UWP负责Page的实例化,因此消除了将依赖项显式注入视图的能力。
最简单的方法是拥有一个可访问的服务定位器,并向其注册您的依赖项。
public sealed partial class App {
public App() {
InitializeComponent();
Container = ConfigureServices();
Suspending += OnSuspending;
}
public static IContainer Container { get; set; }
private IContainer ConfigureServices() {
var containerBuilder = new ContainerBuilder();
// Registers all the platform-specific implementations of services.
containerBuilder.RegisterType<LoggingService>()
.As<ILoggingService>()
.SingleInstance();
containerBuilder.RegisterType<SQLitePlatformService>()
.As<ISQLitePlatformService>()
.SingleInstance();
containerBuilder.RegisterType<DiskStorageService>()
.As<IDiskStorageService>()
.SingleInstance();
containerBuilder.RegisterType<Facade>()
.As<IFacade>();
//...Register ViewModels as well
containerBuilder.RegisterType<SomePageViewModel>()
.AsSelf();
//...
var container = containerBuilder.Build();
return container;
}
//...
}
Run Code Online (Sandbox Code Playgroud)
然后根据需要在视图中解决依赖关系。
internal sealed partial class SomePage {
public SomePage() {
InitializeComponent();
ViewModel = App.Container.Resolve<SomePageViewModel>();
this.DataContext = ViewModel;
}
public SomePageViewModel ViewModel { get; private set; }
protected override void OnNavigatedTo(NavigationEventArgs e) {
ViewModel.LoadAsync();
base.OnNavigatedTo(e);
}
}
Run Code Online (Sandbox Code Playgroud)
另一个更复杂的方法是使用基于约定的方法,然后进入应用程序的“框架”导航。
该计划将订阅该NavigatedTo活动
public interface INavigationService {
bool Navigate<TView>() where TView : Page;
bool Navigate<TView, TViewModel>(object parameter = null) where TView : Page;
}
public class NavigationService : INavigationService {
private readonly Frame frame;
private readonly IViewModelBinder viewModelBinder;
public NavigationService(IFrameProvider frameProvider, IViewModelBinder viewModelBinder) {
frame = frameProvider.CurrentFrame;
frame.Navigating += OnNavigating;
frame.Navigated += OnNavigated;
this.viewModelBinder = viewModelBinder;
}
protected virtual void OnNavigating(object sender, NavigatingCancelEventArgs e) { }
protected virtual void OnNavigated(object sender, NavigationEventArgs e) {
if (e.Content == null)
return;
var view = e.Content as Page;
if (view == null)
throw new ArgumentException("View '" + e.Content.GetType().FullName +
"' should inherit from Page or one of its descendents.");
viewModelBinder.Bind(view, e.Parameter);
}
public bool Navigate<TView>() where TView : Page {
return frame.Navigate(typeof(TView));
}
public bool Navigate<TView, TViewModel>(object parameter = null) where TView : Page {
var context = new NavigationContext(typeof(TViewModel), parameter);
return frame.Navigate(typeof(TView), context);
}
}
Run Code Online (Sandbox Code Playgroud)
然后使用导航参数传递要解析的视图模型类型并将数据绑定到视图。
public interface IViewModelBinder {
void Bind(FrameworkElement view, object viewModel);
}
public class ViewModelBinder : IViewModelBinder {
private readonly IServiceProvider serviceProvider;
public ViewModelBinder(IServiceProvider serviceProvider) {
this.serviceProvider = serviceProvider;
}
public void Bind(FrameworkElement view, object viewModel) {
InitializeComponent(view);
if (view.DataContext != null)
return;
var context = viewModel as NavigationContext;
if (context != null) {
var viewModelType = context.ViewModelType;
if (viewModelType != null) {
viewModel = serviceProvider.GetService(viewModelType);
}
var parameter = context.Parameter;
//TODO: figure out what to do with parameter
}
view.DataContext = viewModel;
}
static void InitializeComponent(object element) {
var method = element.GetType().GetTypeInfo()
.GetDeclaredMethod("InitializeComponent");
method?.Invoke(element, null);
}
}
Run Code Online (Sandbox Code Playgroud)
将Frame通过从当前窗口中提取它的包装服务访问
public interface IFrameProvider {
Frame CurrentFrame { get; }
}
public class DefaultFrameProvider : IFrameProvider {
public Frame CurrentFrame {
get {
return (Window.Current.Content as Frame);
}
}
}
Run Code Online (Sandbox Code Playgroud)
以下扩展类提供实用程序支持
public static class ServiceProviderExtension {
/// <summary>
/// Get service of type <typeparamref name="TService"/> from the <see cref="IServiceProvider"/>.
/// </summary>
public static TService GetService<TService>(this IServiceProvider provider) {
return (TService)provider.GetService(typeof(TService));
}
/// <summary>
/// Get an enumeration of services of type <paramref name="serviceType"/> from the <see cref="IServiceProvider"/>
/// </summary>
public static IEnumerable<object> GetServices(this IServiceProvider provider, Type serviceType) {
var genericEnumerable = typeof(IEnumerable<>).MakeGenericType(serviceType);
return (IEnumerable<object>)provider.GetService(genericEnumerable);
}
/// <summary>
/// Get an enumeration of services of type <typeparamref name="TService"/> from the <see cref="IServiceProvider"/>.
/// </summary>
public static IEnumerable<TService> GetServices<TService>(this IServiceProvider provider) {
return provider.GetServices(typeof(TService)).Cast<TService>();
}
/// <summary>
/// Get service of type <paramref name="serviceType"/> from the <see cref="IServiceProvider"/>.
/// </summary>
public static object GetRequiredService(this IServiceProvider provider, Type serviceType) {
if (provider == null) {
throw new ArgumentNullException("provider");
}
if (serviceType == null) {
throw new ArgumentNullException("serviceType");
}
var service = provider.GetService(serviceType);
if (service == null) {
throw new InvalidOperationException(string.Format("There is no service of type {0}", serviceType));
}
return service;
}
/// <summary>
/// Get service of type <typeparamref name="T"/> from the <see cref="IServiceProvider"/>.
/// </summary>
public static T GetRequiredService<T>(this IServiceProvider provider) {
if (provider == null) {
throw new ArgumentNullException("provider");
}
return (T)provider.GetRequiredService(typeof(T));
}
}
public class NavigationContext {
public NavigationContext(Type viewModelType, object parameter = null) {
ViewModelType = viewModelType;
Parameter = parameter;
}
public Type ViewModelType { get; private set; }
public object Parameter { get; private set; }
}
public static class NavigationExtensions {
public static bool Navigate<TView>(this Frame frame) where TView : Page {
return frame.Navigate(typeof(TView));
}
public static bool Navigate<TView, TViewModel>(this Frame frame, object parameter = null) where TView : Page {
var context = new NavigationContext(typeof(TViewModel), parameter);
return frame.Navigate(typeof(TView), context);
}
}
Run Code Online (Sandbox Code Playgroud)
您可以像启动前一样配置应用程序,但是该容器将用于初始化导航服务,其余部分将由它处理。
public sealed partial class App {
public App() {
InitializeComponent();
Container = ConfigureServices();
Suspending += OnSuspending;
}
public static IContainer Container { get; set; }
private IContainer ConfigureServices() {
//... code removed for brevity
containerBuilder
.RegisterType<DefaultFrameProvider>()
.As<IFrameProvider>()
.SingleInstance();
containerBuilder.RegisterType<ViewModelBinder>()
.As<IViewModelBinder>()
.SingleInstance();
containerBuilder.RegisterType<AutofacServiceProvider>()
.As<IServiceProvider>()
containerBuilder.RegisterType<NavigationService>()
.AsSelf()
.As<INavigationService>();
var container = containerBuilder.Build();
return container;
}
protected override void OnLaunched(LaunchActivatedEventArgs e) {
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame == null) {
rootFrame = new Frame();
rootFrame.NavigationFailed += OnNavigationFailed;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) {
//TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
//Activating navigation service
var service = Container.Resolve<INavigationService>();
if (e.PrelaunchActivated == false) {
if (rootFrame.Content == null) {
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
rootFrame.Navigate<SomePage, SomePageViewModel>();
}
// Ensure the current window is active
Window.Current.Activate();
}
}
public class AutofacServiceProvider : IServiceProvider
public object GetService(Type serviceType) {
return App.Container.Resolve(serviceType);
}
}
//...
}
Run Code Online (Sandbox Code Playgroud)
通过使用以上约定,这些Frame扩展允许进行一些常规导航。
ContentFrame.Navigate<SomeOtherPage, SomeOtherPageViewModel>();
Run Code Online (Sandbox Code Playgroud)
视图可以很简单
internal sealed partial class SomePage {
public SomePage() {
InitializeComponent();
}
public SomePageViewModel ViewModel { get { return (SomePageViewModel)DataContext;} }
protected override void OnNavigatedTo(NavigationEventArgs e) {
ViewModel.LoadAsync();
base.OnNavigatedTo(e);
}
}
Run Code Online (Sandbox Code Playgroud)
由于导航服务还将在导航后设置视图的数据上下文。
导航也可以由已INavigationService注入的视图模型启动
public class SomePageViewModel : ViewModel {
private readonly INavigationService navigation;
private readonly IFacade facade;
public SomePageViewModel(IFacade facade, INavigationService navigation) {
this.navigation = navigation;
this.facade = facade;
}
//...
public void GoToSomeOtherPage() {
navigation.Navigate<SomeOtherPage, SomeOtherPageViewModel>();
}
//...
}
Run Code Online (Sandbox Code Playgroud)