Application.Current 为空,但新的 Application() 仍然失败?



我有一个非托管应用程序,它使用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( 的累积更新,但我不确定这是否是重大更改。

编辑:我更新了代码,现在它又可以工作了。

相关内容

最新更新