我有一个非托管应用程序,它使用WPF程序集作为其某些用户界面。由于这种安排,Application.Current
不会自动创建。因此,当加载第一个 WPF 窗口时,我的代码会这样做:
if (System.Windows.Application.Current == null)
{
new System.Windows.Application();
}
这是第一次有效,是我见过的推荐方法。
但是,如果用户关闭(唯一的(WPF 窗口,然后再次加载它,即使再次Current == null
调用应用程序 ctor 时也会引发异常。
文档中很清楚,每个 AppDomain 只能有一个应用程序 -但是为什么当前为空,但我无法创建它?
引发的异常类型为InvalidOperationException
,并显示以下消息:
无法在 相同的应用程序域。
其InnerException
为空。
为了解决这个问题,我尝试:
使用
ShutdownMode = ShutdownMode.OnLastWindowClose
构造Application
在WPF 窗口关闭时显式调用
Current.Shutdown()
但两者都没有任何区别。
是否有其他方法可以手动管理Current
对象的生存期?还是应该改为尝试在非托管应用程序启动时创建它,然后始终依赖于在进程生存期内设置它?
您链接的文档在其备注部分中声明以下内容:
每个只能创建应用程序类的一个实例 AppDomain,以确保对一组 应用程序范围的窗口、属性和资源数据。因此应用程序类的无参数构造函数检测正在初始化的实例是否是 应用域;如果不是,则抛出 InvalidOperationException。
我强调的部分意味着它不是检查它是否是当前运行的唯一/单个应用程序,而是检查之前是否初始化过任何其他Application
实例(无论它是否已关闭(。
看看Application
类的源代码证实了这一点:Application
类在内部使用静态标志(_appCreatedInThisAppDomain
(,该标志在初始化第一个Application
实例时只设置一次。但显然此标志永远不会重置,这会阻止您在同一 AppDomain 中创建更多Application
实例。
这在WinForms中很容易,在WPF中则不然。
显然,我们没有Application
问题,我们有一个AppDomain
问题。
我为此付出了合理的努力,但无法让它按照我想要的方式运行,即在按下空格键时摧毁旧的然后在新Thread
上重新创建一个AppDomain
,我想这是有道理的,尽管考虑到范围。
这充其量是一种解决方法,在您的情况下甚至可能不是一种选择。
有没有其他方法可以手动管理
Current
的生命周期 对象?
据我所知,简单的答案是在程序的生命周期内维护一个 WPF 消息循环Thread
(通过ShutdownMode.OnExplicitShutdown
(,并根据需要使用该Application.Current.Dispatcher
显示 WPF 对象。
下面是在托管控制台应用程序中实现的意思的示例:
class Program
{
static void Main(string[] args)
{
Thread t = CreateThread();
t.Start();
bool quit = false;
while (!quit)
{
switch(Console.ReadKey().Key)
{
case ConsoleKey.Escape:
Application.Current.Dispatcher.Invoke(() => Application.Current.Shutdown());
quit = true;
break;
case ConsoleKey.W:
Application.Current.Dispatcher.Invoke(() =>
{
var w = new Window() { Width = 500, Height = 500, Title = "WPF Window" };
w.Show();
});
break;
case ConsoleKey.D:
Application.Current.Dispatcher.Invoke(() =>
{
var d = new Window() { Width = 500, Height = 500, Title = "WPF Dialog" };
d.ShowDialog();
});
break;
case ConsoleKey.Spacebar:
//// Nope!
//Application.Current.Dispatcher.Invoke(() => Application.Current.Shutdown());
//t = CreateThread();
//t.Start();
break;
}
};
}
static Thread CreateThread()
{
var t = new Thread(() =>
{
if (System.Windows.Application.Current == null)
{
new System.Windows.Application();
Application.Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
}
Application.Current.Run();
});
t.SetApartmentState(ApartmentState.STA);
return t;
}
}
您需要参考 PresentationCore、PresentationFramework 和 WindowsBase 来构建此示例。
我希望它至少能激励某人。
编辑:仅供参考,这可能不再有效...当我发布它时它有效,现在两天后它没有。昨天安装了 .NET Framework (kb4538122( 的累积更新,但我不确定这是否是重大更改。
编辑:我更新了代码,现在它又可以工作了。