сейчас, для обращения к элементам формы, для каждой функции приходится создавать прокси-функцию с проверкой InvokeRequired и вызовом Invoke.
самое утомительное в данном случае — необходимость объявлять делегаты для каждой функции, со временем их накапливается столько, что рябит в глазах.
Здравствуйте, Аноним, Вы писали:
А>сейчас, для обращения к элементам формы, для каждой функции приходится создавать прокси-функцию с проверкой InvokeRequired и вызовом Invoke. А>самое утомительное в данном случае — необходимость объявлять делегаты для каждой функции, со временем их накапливается столько, что рябит в глазах.
А>существует ли более лаконичный способ?
Сделать набор чего-то типа
public static class MyControlInvoker
{
public void Invoke(this Control ctrl, Action act)
{
if (ctrl.InvokeRequired)
ctrl.Invoke(act);
act();
}
....
}
//using
мyForm.Invoke(()=>MessageBox.Show(msg));
public class InvokeCallHandler : ICallHandler
{
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
var c = (Control)input.Target;
if (c.InvokeRequired)
{
return (IMethodReturn)c.Invoke(getNext(), input, getNext);
}
else
{
return getNext()(input, getNext);
}
}
public int Order
{
get;
set;
}
}
Здравствуйте, Alex Dav, Вы писали:
GZ>>Сделать набор чего-то типа
GZ>>
GZ>>public static class MyControlInvoker
GZ>>{
GZ>> public void Invoke(this Control ctrl, Action act)
GZ>> {
GZ>> if (ctrl.InvokeRequired)
GZ>> ctrl.Invoke(act);
GZ>> act();
GZ>> }
GZ>>....
GZ>>}
GZ>>//using
GZ>>мyForm.Invoke(()=>MessageBox.Show(msg));
GZ>>
AD>А можно подробно рассказать что и для чего каждая строчка? AD>Спасибо.
Ребят, вы что? Прочитать хоть одну книжку по родному языку в падлу?
Окей. Тут используется две технологии: Extentions и Lambda. Кратко на пальцах:
public static void Invoke(this Control ctrl, Action act)
слово this рассказывает нам что данный метод является extension методом, и будет показываться во всех классах Control как евойный собственный. Лишь бы был подключен namespace для этого класса. Такое вот волшебство.
В результате, будьто кнопка или форма, мы вполне можем прописать:
myButton.Invoke....
myForm.Invoke....
Данный метод будет как родной.
Насчет лямбды. Лямбда не является сама по себе делегатом. Для того чтобы лямбду можно было сохранить, нужно что-то типа:
var myDelegate=new MyDelegateType(()=>MessageBox.Show(msg));
Но нас спасает от такого кодовредительства две вещи:
1. С# позволяет не писать new MyDelegateType(...) а написать
var myDelegate = ()=>MessageBox.Show(msg);
такой вот синтаксический сахар.
2. Вместо того чтобы плодить делегаты и типы есть универсальные типы делегатов — Action и Func<Result>. Есть generic версии типа Action<T>, Action<T, T1>...Func<Result,T>, Func<Result,T,T1> но они нас не волнуют, так как задача не так сложна и у нас есть замыкание. Они отличаются лишь тем что делегат Func возвращает значение, а Action не возвращает. С помощью их можно описать любой метод.
Ну и ессно, об Invoke. Если взглянуть рефлектором, то Invoke задействует механизм оконных сообщений для того, чтобы синхронизировать выполнение данной процедуры с тредом в котором выполняется WinForms форма. Если мы уже находимся в данном потоке, о чем нам говорит возвращаемый результат InvokeRequired, то задействовать его и не нужно.
Вот на пальцах и все. Прошу не сравнивать с стандартами, ибо там точнее но зато не на пальцах. За подробностями в стандарты и другую научно-популярную литературу.
GZ>Ребят, вы что? Прочитать хоть одну книжку по родному языку в падлу?
Ну какой же он нам родной — буржуинский же
GZ>Окей. Тут используется две технологии: Extentions и Lambda.
А что бы почитать про них — попроще?
GZ>Кратко на пальцах:... Спасибо.
GZ>
GZ>var myDelegate = ()=>MessageBox.Show(msg);
GZ>
GZ>такой вот синтаксический сахар.
боюсь из-за этого сахара половина даже не поймет, что тут происходит
Здравствуйте, Аноним, Вы писали: А>сейчас, для обращения к элементам формы, для каждой функции приходится создавать прокси-функцию с проверкой InvokeRequired и вызовом Invoke. А>самое утомительное в данном случае — необходимость объявлять делегаты для каждой функции, со временем их накапливается столько, что рябит в глазах. А>существует ли более лаконичный способ?
Аспектное программирование. Например, заюзать PostSharp — бесплатная Community Edition как раз включает Method-Level & Property-Level Aspects. В данном случае способ использования такой: (1) во-первых, создаешь свой аспект наследованием от MethodInterceptionAspect (можешь его создать в отдельной сборке):
Скрытый текст
/// <summary>
/// Аспект перехватывает вызов любого метода с любыми аргументами с любым типом возвращаемого значения.
/// </summary>
[Serializable]
public class ThreadSafeControlMethodAttribute : MethodInterceptionAspect
{
public override void OnInvoke(MethodInterceptionArgs args)
{
// Экземпляр, которому принадлежит данный метод должен быть или наследоваться от Control'аvar control = args.Instance as Control;
if (control != null)
{
if (!control.InvokeRequired()) // для данного вызова метода маршалинг на поток, в котором был создан Control, не требуется
{
args.Proceed();
}
else// для данного вызова требуется маршалинг на поток, в котором был создан Control
{
// Если у аспекта Async = True, то маршалинг будет сделан асинхронным способом через BeginInvoke,
// в этом случае вызывающий поток пойдет работать дальше, не дожидаясь, пока поток Control'а
// исполнит вызов (результатом вызова метода будет IAsyncResult)if (_async)
{
control.BeginInvoke(((Action)(() =>
{
args.Proceed();
})));
}
else// Если Async = False, вызывающий поток будет блокирующе ждать пока поток Control'а исполнит вызов и вернет его результат
{
control.Invoke(((Action)(() =>
{
args.Proceed();
})));
}
}
}
}
bool _async;
public bool Async
{
get
{
return _async;
}
set
{
_async = value;
}
}
}
(2) во-вторых, перед каждым методом формы ставишь такой атрибут:
Скрытый текст
// Такой метод формы будет вызван при помощи Invoke
[ThreadSafeControlMethod]
publicMyRetType MyMethod([[MyType1 myArg1], MyType2 myArg2]...)
{
...
}
// Такой метод формы будет вызван при помощи BeginInvoke
[ThreadSafeControlMethod(Async=true)]
publicMyRetType MyMethod([[MyType1 myArg1], MyType2 myArg2]...)
{
...
}
(3) Ну и, наконец, в-третьих, обращаешься к методам формы как-будто они потокобезопасные, вызов будет автоматически перехвачен аспектом (IL-код перехвата будет сгенерен во время компиляции для каждого метода, помеченного твоим атрибутом), и при необходимости вызван Invoke или BeginInvoke, в зависимости от значения свойства Async атрибута ThreadSafeControlMethod, который ты использовал перед определением этого метода в классе формы.
Re[4]: WinForms и многопоточные приложения
От:
Аноним
Дата:
23.10.10 06:54
Оценка:
GZ>2. Вместо того чтобы плодить делегаты и типы есть универсальные типы делегатов — Action и Func<Result>. Есть generic версии типа Action<T>, Action<T, T1>...Func<Result,T>, Func<Result,T,T1> но они нас не волнуют, так как задача не так сложна и у нас есть замыкание. Они отличаются лишь тем что делегат Func возвращает значение, а Action не возвращает. С помощью их можно описать любой метод.
спасибо за наводку, то что нужно
Re: WinForms и многопоточные приложения
От:
Аноним
Дата:
02.11.10 08:33
Оценка:
Здравствуйте, Аноним, Вы писали:
А>сейчас, для обращения к элементам формы, для каждой функции приходится создавать прокси-функцию с проверкой InvokeRequired и вызовом Invoke. А>самое утомительное в данном случае — необходимость объявлять делегаты для каждой функции, со временем их накапливается столько, что рябит в глазах.
А>существует ли более лаконичный способ?
Здравствуйте, Аноним, Вы писали:
А>сейчас, для обращения к элементам формы, для каждой функции приходится создавать прокси-функцию с проверкой InvokeRequired и вызовом Invoke. А>самое утомительное в данном случае — необходимость объявлять делегаты для каждой функции, со временем их накапливается столько, что рябит в глазах.
А>существует ли более лаконичный способ?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
internal void Print(string s)
{
textBox1.Text = s;
}
private void button1_Click(object sender, EventArgs e)
{
new a(this).Go();
}
}
class a
{
Form1 f;
public a(Form1 f) { this.f = f; }
internal void Go()
{
new Thread(delegate()
{
f.Invoke(new MethodInvoker(delegate()
{
f.Print("fadsfsdf");
}));
}).Start();
}
}
public partial class Form1 : Form
{
private SynchronizationContext cont;
public Form1()
{
InitializeComponent();
cont = SynchronizationContext.Current;
}
private void button1_Click(object sender, EventArgs e)
{
new Thread(delegate()
{
cont.Post(delegate(Object o)
{
this.label1.Text = (string)o;
}, "blablabla");
}).Start();
}
}