【问题标题】:C# WPF - Want to open multiple windows at once, but only one instance of each windowC# WPF - 想要一次打开多个窗口,但每个窗口只有一个实例
【发布时间】:2014-03-31 12:36:54
【问题描述】:

我是 WPF 新手,一直在寻找答案,这肯定不难吗?

我创建了一个主窗口,其中包含指向多个窗口的链接,并且我希望它们以非模式方式彼此并排运行,但我不想打开 SAME 窗口的多个实例。

简单来说,我可以同时打开 Windows A、B、C,但不能同时打开 Windows、A、A、B、C、C。

我需要检查我试图打开的窗口(在本例中为 EditSettings)。

如果打开 - 激活它

如果没有打开,打开它。

我在 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";
        }
    }

}

现在我知道这个逻辑有什么问题 - 每次我按下按钮打开 EditSettings 时,它的设置 isOpen 再次为 null。如果我没有为 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 window


    【解决方案1】:

    有些人可能会接受这个想法,但每当我需要这样做时,我都会将子窗口对象作为应用程序的一部分。然后,在您的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 访问器,让每个人都相当满意。

    【讨论】:

    • 谢谢约翰,如果可能的话,请您确定我将把代码的哪一部分放入子窗口类中?据我了解,“子窗口类”是指将代码放在 EditSettings.xaml.cs 而不是 MainWindow.xaml.cs 中?每个窗口都与另一个窗口完全无关,因此解耦一切都会起作用。我只需要更多关于语法的信息 :) 谢谢
    • 啊,对不起。我想我对此更清楚,因为你已经写过了。 MenuItem_Click() 中的所有内容都可以由类以几乎完全相同的方法进行管理。唯一的区别是winEditSettings 将是一个成员变量,而isOpen 可以被废弃。我会在我的回答中快速重写你的代码,以防这仍然很奇怪。
    【解决方案2】:
                   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();
            }
    

    【讨论】:

      【解决方案3】:

      我的建议是您设置某种形式的计数器。这将防止打开一个以上的窗口实例。

          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"); 
              }
          }
      

      我希望这会有所帮助。

      【讨论】:

      • 谢谢,我已经设法通过迭代 Application.Current.Windows 来阻止多个实例的打开。如果它已经打开,我只是在努力将窗户拉到前面!
      • 我相信你没有创建多个实例的原因是你的 else 语句永远不会被调用。由于存在窗口,它将始终激活,但永远不会出现在前面。我的建议是交换 ActivateShow 方法来测试这个理论。 Show 方法似乎总是将窗口放在我制作的任何应用程序的前面。 ——
      【解决方案4】:

      对于其他有这个问题的人,我找到了另一个解决方案 - 除了它无法将打开的窗口带到前面(激活)之外,它可以工作。但是,它确实可以防止多次打开同一个窗口。

              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(); 
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-11-23
        • 1970-01-01
        • 2016-10-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-04
        相关资源
        最近更新 更多