【问题标题】:How to get a static reference to a WPF Window?如何获取对 WPF 窗口的静态引用?
【发布时间】:2010-02-13 21:43:17
【问题描述】:

我已经尝试了很多方法来在我的程序中获取我的窗口的静态引用。我需要在运行时从不同的类访问它的所有成员,因此需要静态引用。

我想要像Program.Window1 这样的东西,其中Core 是静态的,MyWindow 是它的静态成员之一。

在 WinForms 中,我通常在 Program.cs 中声明我的静态表单,但这似乎不适用于 WPF 及其自定义“App.xaml”ApplicationDefinition。

我该怎么做?

注意:我已经尝试了多种方法:直接调用新窗口(即Program.Window1 = new Window1())将不起作用,因为我遇到了一些线程无效异常。据我所知,只有 ApplicationDefinitions 可以在 WPF 中启动窗口。

每当我尝试“通过代码”而不是通过默认的 XAML ApplicationDefinition 的 StartupUri 创建窗口时,都会出现以下异常:

调用线程必须是 STA,因为很多 UI 组件都需要这个。

【问题讨论】:

  • 如果您需要在代码中创建窗口,则必须使用 [STAThread] 标记 Main 方法。

标签: c# wpf static reference window


【解决方案1】:

创建一个可以包含窗口对象的静态类,然后在创建窗口时,让它自己传递给静态类,从此静态类可以将窗口对象分发给感兴趣的各方,即使窗口对象本身不是静态的。像这样的东西。你的表单不需要是静态的,你只需要一个静态的地方来保存表单对象。

public class Core
{
     internal static MyWindowClass m_Wnd = null;

     // call this when your non-static form is created
     //
     public static void SetWnd(MyWindowClass wnd)
     {
         m_Wnd = wnd;
     }

     public static MyWindow { get { return m_Wnd; } }
}

【讨论】:

    【解决方案2】:

    试试这个 ((MainWindow)App.Current.Windows[0]).MainCanvas。

    【讨论】:

      【解决方案3】:

      使用 WPF 实例化您自己的窗口是绝对可能的。但是,是的,您必须在“UI 线程”(这是一个 STA 线程)上。

      例如,假设我们想在我们的 App 类上拥有一个属性来公开某个窗口。

          public partial class App
          {
              private static Window _myWindow;
      
              public static Window1 MyWindow
              {
                  get
                  {
                      if (_myWindow == null)
                          _myWindow = new Window1();
                      return _myWindow;
                  }
             }
          }
      

      正如您所经历的,这段代码的问题是,根据调用 MyWindow getter 的线程,如果线程不是 STA,new Window1() 将失败。

      要确保在正确的线程上创建窗口,请输入 the Dispatcher object。此对象在整个 WPF 中使用,以确保 UI 元素之间的通信在正确的线程上完成。

      回到我们的new Window1,我们可以使用App.Dispatcher 对象来确保new 操作在主应用程序线程上完成,如下所示:

              public static Window1 MyWindow
              {
                  get
                  {
                      if (_myWindow == null)
                      {
                           var window = 
                                   Application.Current.Dispatcher.Invoke(
                                     new Func<Window1>(() => new Window1()));
      
                          _myWindow = (Window1)window;
                      }
      
                      return _myWindow;
                  }
             }
      

      在这里,我持有当前应用程序的 Dispatcher 对象,并使用执行实际更新的委托调用 InvokeInvoke 确保我的委托在正确的线程上执行,并返回结果。瞧,创建的窗口没有可怕的 STA 错误。

      现在,您必须记住的是,对 MyWindow 实例进行的进一步调用也必须在正确的线程上进行。为了避免在调用 Dispatcher.Invoke 时乱扔代码,将窗口实例包装在一个简单的 API 后面可能很有用。例如。 Show 方法可以这样实现,确保通过窗口的 Dispatcher 对象编组 Show 调用:

              public static void ShowMyWindow()
              {
                  MyWindow.Dispatcher.Invoke(new Action(MyWindow.Show));
              }
      

      【讨论】:

      • 好像比较合适,不过上面的方法比较简单,也行。不过谢谢你的回答。 +1
      【解决方案4】:

      我已经成功地使用了它。声明一个窗口类型的静态变量。然后在窗口的构造函数中将静态变量设置为“this”。我在整个应用程序中都使用了它,它似乎在静态或实例方法中运行良好。

          public static MainWindow screenMain = null;
          public MainWindow()
          {
              InitializeComponent();
      
              screenMain = this;  //static reference to this.
      
          }
      

      例如,我能够做到这一点。

          private delegate void del();
          ....
          screenMain.Dispatcher.Invoke(new del(delegate()
          {
              screenMain.ButtonSubmit.IsEnabled = true;
              screenMain.ButtonPreClearing.IsEnabled = true;
          }));   
      

      【讨论】:

        猜你喜欢
        • 2015-02-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多