.Net Framework 4.5
/* Sandbox.cs
* © Andrey Bushman, 2017
*
* Небольшой пример создания дополнительного потока,
* работающего параллельно с потоком пользовательского
* интерфейса (UI) и обновляющего этот интерфейс по мере
* необходимости. Дополнительных потоков можно создавать
* сколько угодно. В данном примере для простоты создаётся
* только один.
*
* В данном примере вместо прямого использоватия потока
* (Thread) я использую задачу (Task), которая в свою очередь
* использует пул потоков.
*
* Рабочий поток (т.е. задача) вычисляет текущую дату и время,
* после чего записывает их в ListBox, находящийся в потоке UI.
*
* Снятие/установка галочки «Do work» управляет
* стартом/завершением рабочего потока. Кнопка «Clear» очищает
* ListBox и заголовок окна.
*
* В консоль выводятся идентификаторы текущих потоков и маркер
* их принадлежности (или не принадлежности) к пулу потоков.
*
* В данном примере для обращения к потоку UI из рабочего
* потока я использую два способа: диспетчер и контекст
* синхронизации.
*
* В примере используется WPF, но всё то же самое применимо к
* WinForms и ASP.NET.
*/
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
namespace Bushman.Sandbox {
class MyWindow : Window {
SynchronizationContext context = null;
public MyWindow() : base() {
Console.Title = «Sandbox»;
string prefix = «Main Window»;
Title = prefix;
Topmost = true;
Width = 300;
Height = 600;
ResizeMode = ResizeMode.NoResize;
WindowStartupLocation = WindowStartupLocation
.CenterScreen;
Grid grid = new Grid();
grid.RowDefinitions.Add(new RowDefinition());
grid.RowDefinitions.Add(new RowDefinition());
grid.ColumnDefinitions.Add(new ColumnDefinition());
grid.ColumnDefinitions.Add(new ColumnDefinition());
grid.ColumnDefinitions[1].Width = new GridLength(0,
GridUnitType.Auto);
grid.RowDefinitions[1].Height = new GridLength(0,
GridUnitType.Auto);
Content = grid;
Thickness margin = new Thickness(5, 5, 5, 5);
ListBox listbox = new ListBox();
listbox.Margin = margin;
grid.Children.Add(listbox);
listbox.SetValue(Grid.RowProperty, 0);
listbox.SetValue(Grid.ColumnProperty, 0);
listbox.SetValue(Grid.ColumnSpanProperty, 2);
CheckBox chBox = new CheckBox();
chBox.Margin = margin;
chBox.Content = «Do work»;
grid.Children.Add(chBox);
chBox.SetValue(Grid.ColumnProperty, 0);
chBox.SetValue(Grid.RowProperty, 1);
Task task = null;
long i = 0;
chBox.Checked += (s, e) => {
task = new Task(() => {
using (task) {
i = 0;
while (Dispatcher.Invoke(
() => chBox.IsChecked == true) &&
i < long.MaxValue) {
// В рабочем потоке выполняем
// некоторую работу. Например —
// формируем строку текущих даты и
// времени.
string value = DateTime.Now
.ToString(«yyyy-MM-dd hh:mm:ss»
);
// В данном примере мы мы можем
// имитировать длительную работу,
// либо заблокировать эту строку
// кода, если такая имитация нам не
// нужна:
//Thread.Sleep(TimeSpan.FromSeconds
// (1));
Console.WriteLine(
«Current thread Id: {0}. » +
«Is pull thread: {1}»,
Thread.CurrentThread
.ManagedThreadId.ToString(),
Thread.CurrentThread
.IsThreadPoolThread);
// Результат наших «вычислений»
//записываем в поток UI
context.Post(_ => {
listbox.Items.Add(value);
Title = string.Format(
«{0}. Items Count: {1}»,
prefix, i++.ToString());
Console.WriteLine(
«Current thread Id: {0}. » +
«Is pull thread: {1}»,
Thread.CurrentThread
.ManagedThreadId.ToString(),
Thread.CurrentThread
.IsThreadPoolThread);
}, null);
}
}
});
task.Start();
};
chBox.IsChecked = false;
Button button = new Button();
button.Content = «Clear»;
button.Margin = margin;
button.Padding = margin;
grid.Children.Add(button);
button.SetValue(Grid.ColumnProperty, 1);
button.SetValue(Grid.RowProperty, 1);
button.Click += (s, e) => {
listbox.Items.Clear();
Title = prefix;
i = 0;
};
EventHandler action = null;
action = (s, e) => {
context = SynchronizationContext.Current;
Activated -= action;
};
Activated += action;
NameScope.SetNameScope(this, new NameScope());
RegisterName(nameof(listbox), listbox);
RegisterName(nameof(chBox), chBox);
RegisterName(nameof(button), button);
}
}
class Sandbox {
[STAThread]
static void Main(string[] args) {
MyWindow win = new MyWindow();
Application app = new Application();
app.Run(win);
}
}
}
Результат работы кода выглядит следующим образом: