WinForms и многопоточные приложения
От: Аноним  
Дата: 22.10.10 08:31
Оценка:
сейчас, для обращения к элементам формы, для каждой функции приходится создавать прокси-функцию с проверкой InvokeRequired и вызовом Invoke.
самое утомительное в данном случае — необходимость объявлять делегаты для каждой функции, со временем их накапливается столько, что рябит в глазах.

существует ли более лаконичный способ?
Re: WinForms и многопоточные приложения
От: GlebZ Россия  
Дата: 22.10.10 08:49
Оценка: 7 (2) +1
Здравствуйте, Аноним, Вы писали:

А>сейчас, для обращения к элементам формы, для каждой функции приходится создавать прокси-функцию с проверкой 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));
Re[2]: WinForms и многопоточные приложения
От: Alex Dav Россия  
Дата: 22.10.10 10:27
Оценка:
Здравствуйте, GlebZ, Вы писали:

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>


А можно подробно рассказать что и для чего каждая строчка?
Спасибо.
Re[2]: WinForms и многопоточные приложения
От: Аноним  
Дата: 22.10.10 10:53
Оценка:
GZ>Сделать набор чего-то типа

тоже не полностью уловил, единственное что понял так то, что каждый action объявлять еще больше рутины
Re: WinForms и многопоточные приложения
От: QrystaL Украина  
Дата: 22.10.10 12:37
Оценка:
А>существует ли более лаконичный способ?

Например, через Unity и Interception:

    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;
        }
    }
Re[3]: WinForms и многопоточные приложения
От: GlebZ Россия  
Дата: 22.10.10 13:53
Оценка: 1 (1)
Здравствуйте, 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, то задействовать его и не нужно.

Вот на пальцах и все. Прошу не сравнивать с стандартами, ибо там точнее но зато не на пальцах. За подробностями в стандарты и другую научно-популярную литературу.
Re[4]: WinForms и многопоточные приложения
От: Alex Dav Россия  
Дата: 22.10.10 16:24
Оценка:
Здравствуйте, GlebZ, Вы писали:


GZ>Ребят, вы что? Прочитать хоть одну книжку по родному языку в падлу?

Ну какой же он нам родной — буржуинский же

GZ>Окей. Тут используется две технологии: Extentions и Lambda.

А что бы почитать про них — попроще?

GZ>Кратко на пальцах:...

Спасибо.


GZ>
GZ>var myDelegate = ()=>MessageBox.Show(msg);
GZ>

GZ>такой вот синтаксический сахар.
боюсь из-за этого сахара половина даже не поймет, что тут происходит
Re: WinForms и многопоточные приложения
От: Fortnum  
Дата: 22.10.10 18:46
Оценка:
Здравствуйте, Аноним, Вы писали:

А>сейчас, для обращения к элементам формы, для каждой функции приходится создавать прокси-функцию с проверкой 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]
public MyRetType MyMethod([[MyType1 myArg1], MyType2 myArg2]...)
{
...
}

// Такой метод формы будет вызван при помощи BeginInvoke
[ThreadSafeControlMethod(Async=true)]
public MyRetType 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.

А>самое утомительное в данном случае — необходимость объявлять делегаты для каждой функции, со временем их накапливается столько, что рябит в глазах.

А>существует ли более лаконичный способ?


Invoke(new Action(() =>
{
    textBox1.Text = "1";
    textBox2.Text = "2";
    textBox3.Text = "3";
}));
Re: WinForms и многопоточные приложения
От: Suigintou  
Дата: 02.11.10 15:02
Оценка:
Здравствуйте, Аноним, Вы писали:

А>существует ли более лаконичный способ?


AsyncOperation
Re: WinForms и многопоточные приложения
От: ion100 Россия  
Дата: 02.11.10 20:40
Оценка:
Здравствуйте, Аноним, Вы писали:

А>сейчас, для обращения к элементам формы, для каждой функции приходится создавать прокси-функцию с проверкой 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();
        }
    }
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.