Я попробовал огромную сумму способов получить статическую ссылку моего окна через мою программу. Я должен получить доступ ко всем его участникам во времени выполнения от различных классов, таким образом, статическая ссылка необходима.
То, что я хотел бы иметь, является чем-то как Program.Window1
, где Core
статично и MyWindow
один из его статических участников.
В WinForms я обычно объявляю свою статическую форму в Program.cs, но это, кажется, не работает с WPF и их пользовательским "App.xaml" ApplicationDefinition.
Как я могу сделать это?
Примечание: Я уже попробовал много путей: использование прямого вызова нового окна (т.е. Program.Window1 = new Window1()
) не будет работать, поскольку я получаю некоторое недействительное исключение потока. Как я понимаю до сих пор, только ApplicationDefinitions может запустить окна в WPF.
Вот исключение каждый раз, когда я пытаюсь создать окно "кодом" а не ApplicationDefinition XAML по умолчанию StartupUri:
Вызывающим потоком должен быть STA, потому что много компонентов UI требуют этого.
Потому что вы сказали:
сделал на последних спринтах, может быть .
Я склонен согласиться с нечетким леденцом (и + 1 от меня).
Однако, если есть что-то, что вы знаете придется сделать, но это было размещено к самому концу, это просто в неправильном месте, если это может иметь серьезные архитектурные последствия.
Вы можете разбить задачу на анализ и внедрение, при этом (импакт) анализ должен произойти очень рано, чтобы определить, действительно ли будет архитектурное воздействие, а затем реализация запланирована соответствующим образом в зависимости от результата анализа.
-121--1665225-Деление на ноль допустимо для чисел с плавающей точки.
Эти «числа» правильно определены в IEEE 754.
Целочисленное деление на ноль, с другой стороны, выбрасывается, потому что нельзя представить бесконечность как int
.
Создайте статический класс, который может содержать оконный объект, а затем, когда окно будет создано, передать себя статическому классу, с этого момента статический класс может передать оконный объект заинтересованным вечеринкам, даже если сам оконный объект не является статическим. Что-то вроде этого. Нет необходимости в том, чтобы форма была статичной, нужно просто статическое место для хранения объекта формы.
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; } }
}
Создание собственных окон с помощью WPF абсолютно возможно. Но да, вы должны быть в «потоке пользовательского интерфейса» (который является потоком STA).
Например, предположим, что мы хотели бы иметь свойство в нашем классе App, которое предоставляет какое-то окно.
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.
Чтобы убедиться, что окно создается в правильном потоке, введите объект Dispatcher . Этот объект используется во всем WPF, чтобы обеспечить связь между элементами пользовательского интерфейса в правильном потоке.
Вернемся к нашему новому Window1
, мы можем использовать приложение.Объект 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 может быть реализован следующим образом, при этом обязательно маршалируйте вызов Show через объект Dispatcher окна:
public static void ShowMyWindow()
{
MyWindow.Dispatcher.Invoke(new Action(MyWindow.Show));
}