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 - 没有什么能阻止窗口打开不止一次。谢谢你的帮助!

C# WPF - 希望一次打开多个窗口,但每个窗口只能打开一个实例

有些人可能会对这个想法表示赞同,但是每当我需要这样做时,我都会将子窗口对象作为应用程序的一部分。 然后,在您的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(); 

这将阻止打开同一窗口的多个实例,并在用户尝试重新打开窗口时将窗口置于最前面。