C# WPF - 想一次打开多个窗口,但每个窗口只有一个实例
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22761719/
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
C# WPF - Want to open multiple windows at once, but only one instance of each window
提问by QueenSaphos
I am new to WPF and have been hunting for an answer, surely this is not difficult?
我是 WPF 的新手,一直在寻找答案,这肯定不难吗?
I have created a main window with links to multiple windows, and I want them to run modelessly alongside one another, but I don't want to open multiple instances of the SAME window.
我创建了一个主窗口,其中包含指向多个窗口的链接,我希望它们彼此无模式运行,但我不想打开 SAME 窗口的多个实例。
In simple terms, I can have Windows A, B, C open at once, but not Windows, A, A, B, C, C.
简单来说,我可以同时打开 Windows A、B、C,但不能同时打开 Windows、A、A、B、C、C。
I need to implement a check for the window I'm trying to open (in this case, EditSettings).
我需要对我尝试打开的窗口进行检查(在本例中为 EditSettings)。
If open - activate it
如果打开 - 激活它
if not open, open it.
如果没有打开,打开它。
I have the following code in Main, which is not working.
我在 Main 中有以下代码,但它不起作用。
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
EditSettings winEditSettings = new EditSettings();
string isOpen = null;
if (isOpen == "true")
{
winEditSettings.Activate();
}
else
{
winEditSettings.Show();
isOpen = "true";
}
}
}
Now I knowwhat's wrong with this logic - every time I press the button to open EditSettings, it's setting isOpen to null again. If I don't set a value to isOpen, the If condition breaks.
现在我知道这个逻辑有什么问题 - 每次我按下按钮打开 EditSettings 时,它都会再次将 isOpen 设置为 null。如果我没有为 isOpen 设置值,则 If 条件会中断。
I could initialise the variable 'isOpen' as a public variable outside the MenuItem_Click method, but then I think I would need an isOpen variable for each window I create!! Surely there is a better way?
我可以将变量“isOpen”初始化为 MenuItem_Click 方法之外的公共变量,但是我想我创建的每个窗口都需要一个 isOpen 变量!!当然有更好的方法吗?
The other option I tried is:
我尝试的另一个选项是:
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
EditSettings winEditSettings = new EditSettings();
if (winEditSettings.IsLoaded)
{
winEditSettings.Activate();
}
else { winEditSettings.Show(); }
I can't figure out why this isn't working, I tried isVisible, isLoaded, isActive - nothing is stopping the window from opening more than once. Thank you for the help!
我不知道为什么这不起作用,我试过 isVisible、isLoaded、isActive - 没有什么能阻止窗口打开不止一次。感谢您的帮助!
采纳答案by QueenSaphos
For anyone else with this question, I have found another solution - which works except that it doesn't manage to bring the open window to the front (Activate). It does, however, prevent opening the same window more than once.
对于有此问题的其他人,我找到了另一个解决方案 - 除了它无法将打开的窗口带到前面(激活)之外,该解决方案有效。但是,它确实可以防止多次打开同一个窗口。
foreach (Window n in Application.Current.Windows)
if (n.Name == "winEditSettings")
{ winEditSettings.Activate(); }
else
{ winEditSettings.Show(); }
Can anyone speculate on why the window is not brought to the front, with Activate()?
任何人都可以推测为什么不使用 Activate() 将窗口带到前面?
EDIT
编辑
For others with this question, placing the winEditSettings.Activate() outside of the foreach loop does everything I'm trying to achieve:
对于其他有这个问题的人,将 winEditSettings.Activate() 放在 foreach 循环之外可以完成我想要实现的一切:
foreach (Window n in Application.Current.Windows)
if (n.Name == "winEditSettings")
{ }
else
{ winEditSettings.Show(); }
winEditSettings.Activate();
This will stop multiple instances of the same window from opening, and will bring the window to the front if the user attempts to reopen it.
这将阻止打开同一窗口的多个实例,并且如果用户尝试重新打开它,则会将窗口置于最前面。
回答by John C
There are people who'll perhaps throw a fit at the idea, but whenever I've needed to do this, I made the child window objects part of the application. Then, in your MenuItem_Click(), test if winEditSettingsis null, instead.
有些人可能会反对这个想法,但是每当我需要这样做时,我都会将子窗口对象作为应用程序的一部分。然后,在您的MenuItem_Click(), 测试 if winEditSettingsis null,而不是。
It's still a member variable for each window (like your provisional isOpensolution), but having the window objects available can have advantages later, if you need to bridge information between the windows. In my cases, we wanted to be able to close all the child windows together, which (most trivially) meant keeping track of those objects in a central location.
它仍然是每个窗口的成员变量(就像您的临时isOpen解决方案),但是如果您需要在窗口之间桥接信息,那么拥有可用的窗口对象在以后会有优势。在我的例子中,我们希望能够一起关闭所有子窗口,这(最简单的)意味着在一个中心位置跟踪这些对象。
Alternatively, if you want the setup completely decoupled, you could take a singleton-like approach and put the logic into your child window classes. Specifically, you could call EditSettings.Activateand let the class keep track of whether a window needs to be created or the existing window merely Show()n.
或者,如果您希望设置完全解耦,您可以采用类似单例的方法并将逻辑放入您的子窗口类中。具体来说,您可以调用EditSettings.Activate并让该类跟踪是需要创建窗口还是现有窗口仅Show()n。
If I were handed your code to rewrite, I'd move it something like this:
如果我被交给你的代码来重写,我会像这样移动它:
private static EditSettings winEditSettings = null;
public static void WakeUp()
{
if (winEditSettings == null)
{
winEditSettings = new EditSettings();
}
winEditSettings.Activate(); // This may need to be inside the block above
winEditSettings.Show();
}
Both of those are part of the class (static), rather than an instance. Your application object therefore calls EditSettings.WakeUp()inside the original MenuItem_Click(), and never actually sees the child window, itself.
这两个都是类 ( static) 的一部分,而不是一个实例。因此,您的应用程序对象EditSettings.WakeUp()在原始 内部调用MenuItem_Click(),并且从未真正看到子窗口本身。
If you change your mind about the decoupled architecture later, by the way, you can add a getaccessor to your winEditSettingsand keep everybody fairly happy.
如果您稍后改变对解耦架构的看法,顺便说一下,您可以get为您的架构添加一个访问器winEditSettings,让每个人都相当满意。
回答by Dexter90
if (_adCst == null)
{
_adCst = new AddCustomerPage();
_adCst.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen;
_adCst.WindowState = System.Windows.WindowState.Normal;
_adCst.ResizeMode = System.Windows.ResizeMode.NoResize;
_adCst.Activate(); // This may need to be inside the block above
_adCst.Show();
}
else
{
if (!_adCst.IsLoaded == true)
{
_adCst = new AddCustomerPage();
_adCst.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen;
_adCst.WindowState = System.Windows.WindowState.Normal;
_adCst.ResizeMode = System.Windows.ResizeMode.NoResize;
_adCst.Show();
}
_adCst.Activate();
}
回答by Rhys Hamilton
My suggestion would be that you set some form of a counter. This will prevent more than one instance of the window being opened.
我的建议是你设置某种形式的计数器。这将防止打开多个窗口实例。
int windowOpen = 1;
private void button_Click(object sender, RoutedEventArgs e)
{
if (windowOpen == 1)
{
WindowA winA = new WindowA();
winA.Show();
windowOpen++; //increments windowOpen by 1, windowOpen will now = 2
}
else if (windowOpen > 1)
{
MessageBox.Show("Window is already open");
}
}
I hope this helps.
我希望这有帮助。

