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

8
我已经尝试过很多方法来获取窗口的静态引用,以在程序中的不同类中访问其所有成员。因此,需要一个静态引用。
我想要的是像Program.Window1这样的东西,其中Core是静态的,而MyWindow是它的一个静态成员。
在WinForms中,我通常会在Program.cs中声明我的静态表单,但是在WPF中,这似乎不起作用,并且使用自定义的“App.xaml” ApplicationDefinition。
我该如何做呢?
注意:我已经尝试了很多方法:直接调用新窗口(即Program.Window1 = new Window1())不起作用,因为我得到了一些线程无效异常。据我所知,只有ApplicationDefinitions可以在WPF中启动窗口。
每当我尝试创建一个窗口“通过代码”,而不是由默认的XAML ApplicationDefinition的StartupUri时,都会出现以下异常:
“因为许多UI组件都需要它,所以调用线程必须是STA。”

如果您需要在代码中创建窗口,那么您必须使用[STAThread]标记Main方法。 - bohdan_trotsenko
4个回答

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

6

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


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()将失败。
为了确保窗口在正确的线程上创建,需要使用Dispatcher对象。该对象在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对象,并使用一个实际执行新建操作的委托调用Invoke。Invoke确保我的委托在正确的线程上执行,并返回结果。窗口被创建而没有出现可怕的STA错误。
现在,您必须记住的是,在MyWindow实例上进行的进一步调用也必须在正确的线程上进行。为了避免在代码中添加对Dispatcher.Invoke的调用,将窗口实例封装在一个简单的API后面可能会很有用。例如,可以像这样实现Show方法,确保通过窗口的Dispatcher对象进行Show调用:
        public static void ShowMyWindow()
        {
            MyWindow.Dispatcher.Invoke(new Action(MyWindow.Show));
        }

似乎更合适,但上述方法更简单且可行。不过还是感谢您的回答。+1 - Lazlo

2

我已经成功地使用了这个方法。声明一个窗口类型的静态变量,在窗口的构造函数中将静态变量设置为“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;
    }));   

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接