C# WPF - 希望一次打开多个窗口,但每个窗口只能打开一个实例
本文关键字:窗口 一个 实例 WPF 希望 一次 | 更新日期: 2023-09-27 17:55:12
我是WPF的新手,一直在寻找答案,这肯定不难吗?
我创建了一个带有指向多个窗口的链接的主窗口,我希望它们彼此无模式地运行,但我不想打开同一窗口的多个实例。
简单来说,我可以一次打开Windows A,B,C,但不能打开Windows,A,A,B,C,C。
我需要对我尝试打开的窗口进行检查(在本例中为编辑设置)。
如果打开 - 激活它
如果未打开,请将其打开。
我在 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";
}
}
}
现在我知道这个逻辑有什么问题 - 每次我按下按钮打开编辑设置时,它都会再次设置为 Open。如果我未将值设置为 isOpen,则 If 条件将中断。
我可以将变量"isOpen"初始化为 MenuItem_Click 方法之外的公共变量,但我想我创建的每个窗口都需要一个 isOpen 变量!!肯定有更好的方法吗?
我尝试的另一个选项是:
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
EditSettings winEditSettings = new EditSettings();
if (winEditSettings.IsLoaded)
{
winEditSettings.Activate();
}
else { winEditSettings.Show(); }
我不知道为什么这不起作用,我尝试了 isVisible、isLoaded、isActive - 没有什么能阻止窗口打开不止一次。谢谢你的帮助!
有些人可能会对这个想法表示赞同,但是每当我需要这样做时,我都会将子窗口对象作为应用程序的一部分。 然后,在您的MenuItem_Click()
中,测试winEditSettings
是否null
,改为。
它仍然是每个窗口的成员变量(如临时isOpen
解决方案),但是如果需要在窗口之间桥接信息,则以后使窗口对象可用可能会有优势。 在我的案例中,我们希望能够一起关闭所有子窗口,这(最微不足道的)意味着在一个中心位置跟踪这些对象。
或者,如果您希望完全分离设置,则可以采用类似单例的方法,并将逻辑放入子窗口类中。 具体来说,您可以调用 EditSettings.Activate
并让类跟踪是否需要创建窗口或现有窗口仅Show()
n。
如果有人交给我重写你的代码,我会像这样移动它:
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();
}
两者都是类(static
)的一部分,而不是实例。 因此,您的应用程序对象在原始MenuItem_Click()
中调用EditSettings.WakeUp()
,并且永远不会实际看到子窗口本身。
顺便说一下,如果你以后改变了对解耦架构的想法,你可以向winEditSettings
添加一个get
访问器,让每个人都相当满意。
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();
}
我的建议是设置某种形式的计数器。这将防止打开窗口的多个实例。
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");
}
}
我希望这有所帮助。
对于其他有这个问题的人,我找到了另一种解决方案 - 除了它无法将打开的窗口带到前面(激活)之外,它有效。但是,它确实可以防止多次打开同一窗口。
foreach (Window n in Application.Current.Windows)
if (n.Name == "winEditSettings")
{ winEditSettings.Activate(); }
else
{ winEditSettings.Show(); }
谁能推测为什么窗口没有被带到前面,用 Activate()?
编辑
对于有这个问题的其他人,将 winEditSettings.Activate() 放在 foreach 循环之外可以完成我想要实现的一切:
foreach (Window n in Application.Current.Windows)
if (n.Name == "winEditSettings")
{ }
else
{ winEditSettings.Show(); }
winEditSettings.Activate();
这将阻止打开同一窗口的多个实例,并在用户尝试重新打开窗口时将窗口置于最前面。