Консольное приложение выводит текстовую информацию на экран. Требуется дуплицировать текст в окне WPF. Окно создается в отдельном потоке (в том же самом не получается):
var loggerThread = new Thread(() =>
{
var logWindow = new Window
{
Title = "Logger",
Width = 100,
Height = 100
};
var stackPanel = new StackPanel
{
Name = "stackPanel"
};
stackPanel.Children.Add(new TextBlock
{
Name = "textBlock", Text = "new text
"
});
logWindow.Content = stackPanel;
logWindow.ShowDialog();
});
loggerThread.SetApartmentState(ApartmentState.STA);
loggerThread.IsBackground = true;
loggerThread.Start();
Как можно добавлять строки в textBlock из разных классов приложение? Или в общем, как получить доступ к UI элементам внутри отдельного потока loggerThread?
Ответ
Очень просто.
Из вашего UI-потока, сохраните значение Dispatcher.CurrentDispatcher в глобальное место. (Вы можете ещё воспользоваться Dispatcher.FromThread из главного потока, но вы должны быть уверены, что диспетчер в UI-потоке уже создан.) Пусть это «глобальное место» называется dispatcher
Теперь вы можете отправлять код в UI-поток, используя dispatcher.BeginInvoke или dispatcher.InvokeAsync
await dispatcher.InvokeAsync(() => textBlock.Text = "Всем привет!");
Кстати, вам скорее всего бы не понадобился дополнительный поток, если бы вы отмаркировали функцию Main атрибутом [STAThread]. Но при этом для длительных синхронных операций (а такие обычно часто встречаются в консольных программах) вам всё равно понадобился бы фоновый поток.
Вот более современная версия DispatcherThread
public class DispatcherThread : IDisposable
{
readonly Dispatcher dispatcher;
readonly Thread thread;
static public async Task
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
return await waitCompletionSource.Task;
}
private DispatcherThread()
{
dispatcher = Dispatcher.CurrentDispatcher;
thread = Thread.CurrentThread;
}
public DispatcherOperation Execute(Action a) => dispatcher.InvokeAsync(a);
public DispatcherOperation
public async Task CloseAsync()
{
var waitCompletionSource = new TaskCompletionSource
public void Dispose()
{
dispatcher.InvokeShutdown();
if (thread != Thread.CurrentThread)
thread.Join();
}
}
Пользоваться просто:
DispatcherThread dt = await DispatcherThread.CreateAsync();
Window w = await dt.Get(() =>
{
var w = new Window() { Height = 100, Width = 100, Content = "hello world" };
w.Show();
return w;
});
// ...
await dt.Execute(() => w.Content = "goodbye world");
// ...
await dt.Execute(() => w.Close());
await dt.CloseAsync();
dt.Dispose();
Комментариев нет:
Отправить комментарий