Как получить статическую ссылку на окно 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; } }
}
абсолютно возможно создать экземпляр собственной 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;
}));