Созадем обычное консольное приложение на .net framework.
Теперь необходимо добавить зависимости: WindowsBase, PresentationCore, PresentationFramework.
Добавим класс нашего окна, унаследовав его от стандартных окон винды.
public class MyWindow : Window{}
Добавим методу main атрибут [STAThread]
А подробнее.
[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.
Спасибо с# чату в тг и пользователю Юрий.
Комментарии (10)
iliazeus
27.01.2019 07:59Добавим методу main атрибут [STAThread]
Зачем?
А действительно, зачем? Из приведенной ссылки это не слишком понятно.
Если мы теперь вызовем на окне метод Show(), оно тут же схлопнется, а так как нам бы хотелось на него смотреть все время, то это окно нужно запихнуть в контейнер, который поддерживает весь жизненный цикл.
Почему вам не подошел Window.ShowDialog()?Larymar Автор
27.01.2019 11:59он захватывает фокус, а я хотел добиться стандартного поведения окна
Думаю, я внес уточнения и теперь «зачем» стал куда более понятным
fedorro
27.01.2019 11:02+1Окно отображается, а после закрывается т.к. выполнение кода заканчивается и окно закрывается, и,! внезапно!, нужен цикл обработки событий. (Ну или просто Thread.Sleep(10000) воткнуть если нужно только показать окно). Кроме того Ваш код нерабочий: Task.Delay(1000); без Wait ничего не ждет, а Application.Current.Shutdown(); свалится с исключением межпоточного взаимодействия — даже проверил специально. Если хотите и окно и консоль — сделайте оконное приложение и в свойствах проекта выберите тип «Консольное приложение».
Larymar Автор
27.01.2019 11:51Спастбо, вы правы, а я при написании поста допустил грубую ошибку по причине версионирования
addewyd
27.01.2019 13:43Так, наверное, было бы интереснее:
using System.Xml; using System.Windows.Markup; namespace ConsoleApplication1 { internal class Program { [STAThread] public static void Main(string[] args) { XmlTextReader r = new XmlTextReader("MyWindow.xaml"); var app = new Application(); app.MainWindow = XamlReader.Load(r) as Window; app.MainWindow.Show(); // ... etc
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" HorizontalAlignment="Left" Margin="80,53,0,0" VerticalAlignment="Top" RenderTransformOrigin="0.5,0.5" Width="127"> </Label> <Button Content="Button" HorizontalAlignment="Left" Height="40" Margin="80,105,0,0" VerticalAlignment="Top" Width="144"/> <!-- и т.д. по вкусу --> </Grid> </Window>
mayorovp
28.01.2019 10:21Вот так не проще ли?
app.Dispatcher.InvokeAsync((Action)(async () => { await Task.Delay(1000); app.Shutdown(); })); app.Run(win);
xystarcha
29.01.2019 20:13Как-то переусложнено. Мы готовим обычный WPF класс, потом
var thread = new Thread(() => { mywindow = new MyWindow(); mywindow.Show(); Dispatcher.Run(); }); thread.SetApartmentState(ApartmentState.STA); thread.Start(); ... var dispatcher = Dispatcher.FromThread(thread); dispatcher.InvokeShutdown();
Никаких STA на главном потоке, никаких связей с Application.
vasyan
Интересно, то что эта статья видна в списке английских статей — это баг или фича?
Larymar Автор
спасибо
почему-то дефолтный был англ, вроде поправил