- Хроники. - -
Мультипоточность в Windows.Forms и WPF
Posted By Ikutsin On 12 февраля 2009 @ 10:45 In .NET C# | Comments Disabled
При создании более или менее сложных приложений для Windows. Неизбежно возникает проблема организации доступа к данным из разных потоков. В Windows.Forms это выглядит так:
Cross-thread operation not valid: Control ‘textBox1’ accessed from a thread other than the thread it was created on.
В WPF это выглядит так:
System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it.
В обеих технологиях есть разные, но простые способы это решить.
Следующий код выкинет исключение:
namespace TestMultithreading
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
(new Action(TestThreading)).BeginInvoke(null, null); //Async. delegate call.
textBox1.Text = "Same thread";
}
void TestThreading()
{
Thread.Sleep(100);
textBox1.Text = "Async change"; //Exception here.
}
}
}
Для решения проблемы, нужно проверить, действительно ли доступ до формы пытается получить другой процесс. Создать поток в контексте формы.
Для этого, можно создать форме новый потоко-независимый метод. Мой называется AddText. Модифицированный класс выглядит следующим образом:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
(new Action(TestThreading)).BeginInvoke(null, null);
textBox1.Text = "Same thread";
}
void TestThreading()
{
Thread.Sleep(1000);
AddText("Async change");
}
public void AddText(string text)
{
if (this.textBox1.InvokeRequired)
{
Action updaterdelegate = new Action (AddText);
try
{
this.Invoke(updaterdelegate, new object[] { text });
}
catch (ObjectDisposedException ex) { }
}
else
{
textBox1.Text = text;
}
}
}
После вызова AddText происходит проверка InvokeRequired, если сребуется Invoke, то он делается через делегат со значением того-же метода.
В WPF получить исключение можно тем-же образом как и в Windows.Forms:
namespace WpfApplication1
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
(new Action(TestThreading)).BeginInvoke(null, null);
}
void TestThreading()
{
textBox1.Text = "Async call"; //
}
}
}
Для решения задачи не требуется проверок. Дело в том, что все изменения контролируются так называемым Dispatcher-ом. Он инкапсулирован в класс
DispatcherObject, который в свою очередь является родителем DependencyObject, UIElement и соответственно всех визуальных элементов WPF. Раскрытие всех тонкостей Диспечера, задача не этой статьи. Для начала, достаточно разобраться с приоритетами (DispatcherPriority) [1].
Вот пример решения для WPF:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
(new Action(TestThreading)).BeginInvoke(null, null);
}
void TestThreading()
{
Thread.Sleep(1000);
Dispatcher.BeginInvoke(new Action(s =>
{
textBox1.Text = s;
}), DispatcherPriority.Render, "AsyncCall");
}
}
Article printed from Хроники.:
URL to article: /792-multipotochnost-v-windowsforms-i-wpf
URLs in this post:
[1] приоритетами (DispatcherPriority): http://msdn.microsoft.com/ru-ru/library/system.windows.threading.dispatcherpriority.aspx
Click here to print.
Copyright © 2008 Все, что меня окружает. All rights reserved.