Как получить статическую ссылку на окно WPF?

Я пробовал огромное количество способов получить статическую ссылку на мое окно в моей программе. Мне нужно получить доступ ко всем его членам во время выполнения разных классов, так что статическая ссылка.

то, что я хотел бы иметь, это что-то вроде Program.Window1, где Core статический и MyWindow один из его статических членов.

в WinForms я обычно объявляю свою статическую форму в программе.cs, но это, похоже, не работает с WPF и их пользовательским "приложением.код XAML" ApplicationDefinition.

как я могу это сделать?

Примечание: я уже пробовал несколько способов: используя прямой вызов нового окна (т. е. Program.Window1 = new Window1()) не будет работать, так как я получаю исключение недействительности потока. Насколько я понимаю, только ApplicationDefinitions может запускать windows в WPF.

вот исключение всякий раз, когда я пытаюсь создать окно "по коду", а не по умолчанию XAML ApplicationDefinition StartupUri:

призвание поток должен быть STA, потому что многие компоненты пользовательского интерфейса требуют этого.

4 ответов


создайте статический класс, который может содержать объект window, а затем, когда окно будет создано, передайте его статическому классу, с этого момента статический класс может передать объект window заинтересованным сторонам, даже если сам объект window не является статическим. Что-то вроде этого. Нет необходимости в том, чтобы ваша форма была статичной, вам просто нужно статическое место для хранения объекта формы.

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

попробуйте это ((MainWindow)приложение.Текущий.Windows[0]).MainCanvas.


абсолютно возможно создать экземпляр собственной windows с помощью WPF. Но да, вы должны быть в "потоке пользовательского интерфейса" (который является потоком STA).

например, скажем, что мы хотели бы иметь свойство в нашем классе приложений, которое предоставляет некоторое окно.

    public partial class App
    {
        private static Window _myWindow;

        public static Window1 MyWindow
        {
            get
            {
                if (_myWindow == null)
                    _myWindow = new Window1();
                return _myWindow;
            }
       }
    }

проблема с этим кодом, как вы испытали, в зависимости от того, какой поток вызывает геттер MyWindow,new Window1() произойдет сбой, если поток не является STA.

чтобы убедиться, что окно создается в правом потоке, введите диспетчер объекта. Этот объект используется во всем WPF, чтобы убедиться, что связь между элементами пользовательского интерфейса выполняется в правильном потоке.

вернемся к нашим new Window1, мы можем использовать приложение.Объект диспетчера, чтобы убедиться, что 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;
            }
       }

здесь я завладеваю объектом диспетчера текущего приложения и вызывает Invoke с делегатом, который делает настоящее новшество. Invoke гарантирует, что мой делегат выполняется в правильном потоке и возвращает результат. Вуаля, окно создается без страшной ошибки STA.

теперь вы должны иметь в виду, что дальнейшие вызовы, сделанные на экземпляре MyWindow, также должны быть сделаны в правильном потоке. Чтобы избежать засорения кода звонками диспетчеру.Invoke, может быть полезно обернуть экземпляр окна за простой API. Е. Г. метод может быть реализован такой, убедитесь в том, чтобы маршалировать вызов шоу через объект диспетчера окна:

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

я использовал это с успехом. Объявите статическую переменную типа window. Затем в конструкторе окна установите статическую переменную в "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;
    }));