Prism.Wpf从自定义Main函数中启动遇到的问题
Posted lishuangquan1987
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Prism.Wpf从自定义Main函数中启动遇到的问题相关的知识,希望对你有一定的参考价值。
最近想整一个插件式开发框架,想把UI做成一个类库,从另外一个类库的Main函数去启动它,当然UI肯定要用到MVVM框架Prism,插件开发时,窗体Show出来还要进行其他一些列的操作,才调用App.Run方法,为了保持运行顺畅,做了不少功课。
之前我写过一篇文章,里面讲解Prism的使用:https://blog.csdn.net/lishuangquan1987/article/details/105014992
通过查看Prism的源码,Container容器是在OnStartup函数中初始化的:
PrismApplicationBase.cs:
/// <summary>
/// The dependency injection container used to resolve objects
/// </summary>
public IContainerProvider Container => _containerExtension;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
InitializeInternal();
}
/// <summary>
/// Run the initialization process.
/// </summary>
void InitializeInternal()
{
ConfigureViewModelLocator();
Initialize();
OnInitialized();
}
/// <summary>
/// Runs the initialization sequence to configure the Prism application.
/// </summary>
public virtual void Initialize()
{
_containerExtension = CreateContainerExtension();
_moduleCatalog = CreateModuleCatalog();
RegisterRequiredTypes(_containerExtension);
RegisterTypes(_containerExtension);
_containerExtension.FinalizeExtension();
ConfigureServiceLocator();
ConfigureModuleCatalog(_moduleCatalog);
var regionAdapterMappins = _containerExtension.Resolve<RegionAdapterMappings>();
ConfigureRegionAdapterMappings(regionAdapterMappins);
var defaultRegionBehaviors = _containerExtension.Resolve<IRegionBehaviorFactory>();
ConfigureDefaultRegionBehaviors(defaultRegionBehaviors);
RegisterFrameworkExceptionTypes();
var shell = CreateShell();
if (shell != null)
{
RegionManager.SetRegionManager(shell, _containerExtension.Resolve<IRegionManager>());
RegionManager.UpdateRegions();
InitializeShell(shell);
}
InitializeModules();
}
其中,这一句_containerExtension = CreateContainerExtension();
执行创建容器方法,方法是一个虚方法,在PrismApplication中实现:
protected override IContainerExtension CreateContainerExtension()
{
return new UnityContainerExtension();
}
要自定义Main函数启动,肯定要自己Show窗口,为了能保证用到IOC,窗口的实例需要使用Container对象,也就是在Show窗体之前,Container是要被初始化的。问题就出现在了这里:
OnStartup何时执行
看微软的源码,OnStartup是在Application的构造函数中执行的:
public Application()
{
EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordGeneral | EventTrace.Keyword.KeywordPerf, EventTrace.Event.WClientAppCtor);
lock (_globalLock)
{
if (_appCreatedInThisAppDomain)
{
throw new InvalidOperationException(SR.Get("MultiSingleton"));
}
_appInstance = this;
IsShuttingDown = false;
_appCreatedInThisAppDomain = true;
}
base.Dispatcher.BeginInvoke(DispatcherPriority.Send, new DispatcherOperationCallback(StartDispatcherInBrowser), null);
base.Dispatcher.BeginInvoke(DispatcherPriority.Send, (DispatcherOperationCallback)delegate
{
if (IsShuttingDown)
{
return null;
}
StartupEventArgs startupEventArgs = new StartupEventArgs();
OnStartup(startupEventArgs);
if (startupEventArgs.PerformDefaultAction)
{
DoStartup();
}
return null;
}, null);
}
但是,事实是这样的吗??
经过调试发现:
在执行app.Run的时候才会执行OnStartup
由于app.Run方法是阻塞的,没法在Run之后去show窗体,更没法在Run之后去执行其他操作。
解决办法
1.设置App.xaml生成操作为Page,因为我们不从它启动:
2.在App的构造函数中主动调用父类的OnStartup方法,就是为了让Container初始化:
public partial class App : PrismApplication
{
public App()
{
base.OnStartup(null);//初始化容器
}
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
}
protected override Window CreateShell()
{
return null;
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
}
}
3.编写Main函数:
public class Test
{
[STAThread]
public static void Main()
{
App app = new App();
app.InitializeComponent();
var window = app.Container.Resolve<MainWindow>();
window.Show();
//执行其他操作,比如加载其他插件,并且与UI交互
app.Run();
}
}
此解决方法的缺陷
缺陷就是,在构造函数中主动调用了父类的OnStartup方法,最后执行app.Run的时候,又会调用一次,貌似没有什么其他问题,但是必须要注意~~
以上是关于Prism.Wpf从自定义Main函数中启动遇到的问题的主要内容,如果未能解决你的问题,请参考以下文章