如何获得WPF窗口的静态引用?

时间:2010-02-13 21:43:18

标签: c# wpf static reference window

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

我想要的是Program.Window1,其中Core是静态的,MyWindow是其静态成员之一。

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

我该怎么做?

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

每当我尝试按“代码”而不是默认的XAML ApplicationDefinition的StartupUri创建窗口时,这是个例外:

  

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

4 个答案:

答案 0 :(得分:11)

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

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

答案 1 :(得分:5)

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

答案 2 :(得分:4)

绝对可以使用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));
        }

答案 3 :(得分:2)

我成功地使用了它。声明窗口类型的静态变量。然后在窗口的构造函数中将静态变量设置为&#34; this&#34;。我在整个应用程序中使用它,它似乎在静态或实例方法中工作正常。

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