Pull to refresh

Если окна открывают, значит — это кому-нибудь нужно

Reading time 2 min
Views 5.9K
Однажды мне потребовалось открыть окно из консольного приложения. Я хотел это сделать используя wpf, но информации, разбросанной по сети оказалось мало, так что я решил как-то систематизировать и представить этот маленький туториал.

Созадем обычное консольное приложение на .net framework.



Теперь необходимо добавить зависимости: WindowsBase, PresentationCore, PresentationFramework.



Добавим класс нашего окна, унаследовав его от стандартных окон винды.

 public class MyWindow : Window{}

Добавим методу main атрибут [STAThread]

Зачем
STAThreadAttribute по существу является обязательным требованием для обмена сообщениями с сервером сообщений Windows с компонентами COM
А подробнее.


[STAThread]
public static void Main(string[] args){}

Теперь создадим наше окно:

 [STAThread]
public static void Main(string[] args)
{
    var win = new MyWindow { Width = 350, Height = 350};
    var grid = new Grid();
    var text = new TextBox {Text = "my text"};
    grid.Children.Add(text);
    win.Content = grid;
}

Если мы теперь вызовем на окне метод Show(), оно тут же схлопнется, а так как нам бы хотелось на него смотреть все время, то это окно нужно запихнуть в контейнер, который поддерживает весь жизненный цикл.

app.MainWindow = win;
app.MainWindow.Show();        
app.Run();

Мы отобразили окно, и оно неплохо себя чувствует, но закрыть его из кода так просто не получится: метод Run() — являет из себя бесконечный цикл, а остановить Application можно только из того же потока, где он вызван. Выход:


 Task.Run(async  () =>
            {
                await  Task.Delay(1000);
               app.Dispatcher.Invoke((Action) delegate { app.Shutdown(); });
            });
;

Тогда весь метод выглядит
так.
[STAThread]
        public static void Main(string[] args)
        {
            var app = new Application();
            var win = new MyWindow { Width = 350, Height = 350};
            var grid = new Grid();
            var text = new TextBox {Text = "my text"};
            grid.Children.Add(text);
            win.Content = grid;
            app.MainWindow = win;
            app.MainWindow.Show();
           Task.Run(async  () =>
            {
                await  Task.Delay(1000);
               app.Dispatcher.Invoke((Action) delegate { app.Shutdown(); });
            });
            app.Run();
        }

а тут исходник


Приятным решением будет не составлять наше окно из кода, а перейти к более привычному xaml.

Для этого добавляем зависимость System.Xml.
И составляем xaml документ.
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:ConsoleApplication1"
    mc:Ignorable="d"
    Title="MyWindow" Height="450" Width="800">
    <Grid>
        <Label Content="Label" />
    </Grid>
</Window>


Теперь загружаем данные из файла.
XmlTextReader r = new XmlTextReader("MyWin.xaml");
var win = XamlReader.Load(r) as Window;


И в таком варианте конечный Main выглядит
так.
[STAThread]
        public static void Main(string[] args)
        {
            var app = new Application();
            XmlTextReader r = new XmlTextReader("MyWin.xaml");
            var win = XamlReader.Load(r) as Window;
            app.MainWindow = win;
            app.MainWindow.Show();
            Task.Run(async  () =>
            {
                await  Task.Delay(1000);
               app.Dispatcher.Invoke((Action) delegate { app.Shutdown(); });
            });
            app.Run();
        }



P.S.
Спасибо с# чату в тг и пользователю Юрий.
Tags:
Hubs:
+8
Comments 15
Comments Comments 15

Articles