wpf 窗口关闭后无法设置可见性或调用 Show、ShowDialog 或EnsureHandle
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23363202/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Cannot set visibility or call Show, ShowDialog or EnsureHandle after a window has been closed
提问by Nzall
This is my App constructor for my WPF application:
这是我的 WPF 应用程序的 App 构造函数:
public partial class App
{
public App()
{
Run(new Login(false));
}
}
And this is my Login constructor:
这是我的登录构造函数:
public Login(bool ignoreSettings)
{
InitializeComponent();
if (ignoreSettings)
{
TxtUsername.Text = SettingsSaver.LoadUsername();
TxtCrmUrl.Text = SettingsSaver.LoadCrmUrl();
return;
}
if (string.IsNullOrWhiteSpace(SettingsSaver.LoadUsername()) || string.IsNullOrWhiteSpace(SettingsSaver.LoadCrmUrl())) return;
try
{
CrmConnector.ConnectToCrm();
MainWindow mainWindow = new MainWindow();
mainWindow.Show();
}
catch (SecurityAccessDeniedException)
{
MessageBox.Show(@"Uw inloggegevens zijn niet correct. Gelieve deze te controleren en opnieuw te proberen.");
}
finally
{
Close();
}
}
It starts the App constructor and goes through the Login constructor just fine, but once it reaches the App Constructor again after finishing the Login constructor, it crashes with an InvalidOperationException, with additional information: "Cannot set visibility or call Show, ShowDialog, or WindowInteropHelper.EnsureHandle after the window has been closed.
它启动 App 构造函数并通过 Login 构造函数就好了,但是一旦它在完成 Login 构造函数后再次到达 App Constructor,它就会因 InvalidOperationException 而崩溃,并带有附加信息:“无法设置可见性或调用 Show、ShowDialog 或 WindowInteropHelper .EnsureHandle 窗口关闭后。
The goal of the constructor is as follows: When the application is first started, I want to check if there are existing settings for this application. If they exist, I want to use those settings to connect to a 3rd party (Dynamics CRM 2011), open the main application window, and then close the Login screen. if they are not there, I want the user to set the settings.
构造函数的目标如下:当应用程序第一次启动时,我想检查这个应用程序是否有现有的设置。如果它们存在,我想使用这些设置连接到第 3 方 (Dynamics CRM 2011),打开主应用程序窗口,然后关闭登录屏幕。如果他们不在那里,我希望用户设置设置。
HOWEVER, I also want to be able to start this window from a button on my main screen, in which case it should ignore the default settings and launch the login window again, allowing me to set the settings again.
但是,我还希望能够从主屏幕上的按钮启动此窗口,在这种情况下,它应该忽略默认设置并再次启动登录窗口,以便我再次设置设置。
I already managed to get it to work using 2 constructors, but Resharper complains when i does that because I basically ignore the parameter in the second constructor (the one which I launch from the button on the main screen. I'm trying to have 1 unified constructor so Resharper does not complain. Is that possible?
我已经设法使用 2 个构造函数让它工作,但是当我这样做时 Resharper 抱怨,因为我基本上忽略了第二个构造函数中的参数(我从主屏幕上的按钮启动的那个。我试图有 1统一构造函数,所以 Resharper 不会抱怨。这可能吗?
Edit: I don't want to keep my login window because I create a new window when I change the settings, using the following code in my MainWindow:
编辑:我不想保留我的登录窗口,因为我在更改设置时创建了一个新窗口,在我的 MainWindow 中使用以下代码:
private void BtnSettings_Click(object sender, RoutedEventArgs e)
{
Login login = new Login(true);
login.Show();
Close();
}
edit: some clarification: I don't want to show multiple windows. What I want is:
编辑:一些说明:我不想显示多个窗口。我想要的是:
- on startup, launch Login.xaml;
- when Login.xaml is launched, check if the settings have already been set;
- if no settings, show Login.Xaml for setting;
- if Settings set, start MainWindow with saved settings.
- 启动时,启动 Login.xaml;
- 当 Login.xaml 启动时,检查设置是否已经设置;
- 如果没有设置,显示 Login.Xaml 进行设置;
- 如果设置了设置,则使用保存的设置启动 MainWindow。
In addition, I have a button on MainWindow which has to force-start Login.xaml but not check if there are settings. These are currently separate constructors and I would like to make 1 constructor of them.
另外,我在 MainWindow 上有一个按钮,它必须强制启动 Login.xaml 但不检查是否有设置。这些目前是单独的构造函数,我想为它们制作 1 个构造函数。
采纳答案by satnhak
Your update makes it a bit clearer what it is you want to achieve. I suggest restructuring the Loginwindow to make it more single responsibility and pushing the validation logic up into the Appclass so that it is responsible for managing initialization flow. A recipe is as follows:
您的更新使您想要实现的目标更加清晰。我建议重构Login窗口以使其职责更加单一,并将验证逻辑推入App类中,以便它负责管理初始化流程。一个食谱如下:
Alter App.Xaml.csso that it looks something like this; importantly there is no StartupUri:
改变App.Xaml.cs它看起来像这样; 重要的是没有StartupUri:
<Application
x:Class="MyNamespace.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources />
</Application>
Where MyNamespaceis the namespace of your Appclass.
MyNamespace你的App类的命名空间在哪里。
Now you are going to manually start the application from App.OnStartup
现在您要手动启动应用程序 App.OnStartup
public partial class App
{
protected override void OnStartup(System.Windows.StartupEventArgs e)
{
base.OnStartup(e);
if (!AreSettingsSet())
{
this.MainWindow = new Login();
this.MainWindow.ShowDialog(); // Waits until closed.
// Recheck the settings now that the login screen has been closed.
if (!AreSettingsSet())
{
// Tell the user there is a problem and quit.
this.Shutdown();
}
}
this.MainWindow = new MainWindow();
this.MainWindow.Show();
}
private bool AreSettingsSet()
{
// Whatever you need to do to decide if the settings are set.
}
}
To summarise: remove your validation logic from the Loginwindow to App, only show Loginif needed and only show MainWindowif the settings are actually valid.
总结一下:将您的验证逻辑从Login窗口中移除到App,仅Login在需要时显示,并且仅MainWindow在设置实际有效时才显示。
回答by Mikael Ohlsson
Try Visibility.Hidden instead of Close if you want to keep it
如果您想保留它,请尝试 Visibility.Hidden 而不是 Close
Update: this.Visibility=Visibility.Hidden;
更新:this.Visibility=Visibility.Hidden;
回答by Sinatr
You will need to do some tweaking and then you can show several windows or single window multiple times.
您需要进行一些调整,然后才能多次显示多个窗口或单个窗口。
- Remove
StartupUrifrom App.xaml. - Set Build action to
Pagefor App.xaml.
StartupUri从 App.xaml 中删除。Page为 App.xaml设置构建操作。
This will disable autogenerating of App.g.ics and you can create own application entry point:
这将禁用 App.g.ics 的自动生成,您可以创建自己的应用程序入口点:
public partial class App : Application
{
[STAThread]
public static void Main()
{
App app = new App();
app.InitializeComponent();
app.ShowWindow1();
app.ShowWindow1(); // show second time same window (new instance)
}
public void ShowWindow1()
{
// show window1 in separate method, so that instance will be deleted after method ends
Window1 window1 = new Window1();
// optional (as it seems)
// MainWindow = window1
widow1.Show();
}
}

