[.NET] Проблема с асинхронным вызовом делегата и датабиндингом

bastii


delegate Result FuncDelegate(string s, IList list);

private void button1_Click(object sender, EventArgs e)
{
bindingSource1.Clear;
FuncDelegate fd = new FuncDelegate(this.Func);
fd.BeginInvoke(textBox1.Text, bindingSource1, FuncFinished, fd);
}

private void FuncFinished(IAsyncResult ar)
{
FuncDelegate fd = (FuncDelegate)ar.AsyncState;
Result r = fd.EndInvoke(ar);
this.Invoke(new EventHandler(delegate
{
toolStripStatusLabel1.Text = r.ToString;
};
}
Здесь bindingSource1 типизированный источник данных для датагрида на форме, а this.Func метод у формы, который добавляет вычисленные объекты в bindingSource1 (он передается как второй параметр типа IList). Сначала сделал синхронно, но Func выполняется довольно долго, поэтому переделал на асинхронный вызов. Проблема в том, что прога в процессе вычисления подвисает, правда не сразу, а после того как часть добавленных объектов появляются в датагриде. Единственная версия заключается в том, что когда вызывается Add в Func, то bindingSource1 вызывает соответствующий обработчик в датагриде, но в контексте рабочего потока, что и вызывает проблемы у датагрида. Соответственно вопрос, как эту ситуацию правильно исправить?

bastii

Интересен вариант, когда саму Func менять не придется.

Dasar

Работа с контролами должна выполняться из основного потока.
Соответственно Add должен тоже вызываться из основного потока.

bastii

А что делать, если Func библиотечная, рассчитанная на IList. В голову приходит идея, когда bindingSource1 передается не напрямую, а через врапер, который будет делегировать каждый метод IList через Control.Invoke. Интересно, может можно приспособить что-нибудь готовое.

bastii

Сделал врапер IList на Add через Control.Invoke. Но работает хреново , много аддов забивают гуи поток, интерфейс почти не реагирует. А можно как-то у BindingSource отцеплять (это можно делать из гуи потока) BindingList на некоторое время , чтобы можно было из рабочего потока сделать серию аддов, а потом подцепить назад (тоже можно делать из гуи потока)?

Dasar

Проще сделать, чтобы Add-ы делались не по одному, а сразу пачкой.
т.е. адаптер IList-а добавляет в tmp, далее из основного потока из tmp сразу пачкой делаются Add-ы.
Для ускорения добавления можно делать BeginUpdate/EndUpdate

bastii

А как правильно это реализовать? Проблема в том, чтобы врапер правильно возвращал индекс в методе Add. Хотя тут может лучше совсем свой BindingList делать как DataSource в BindingSource, который будет thread safe, а события в гуи будет как-то пакетно поднимать. Правда там очень много чего реализовывать получается.

Dasar

Func совсем нельзя переписать?

Dasar

и зачем тебе адаптер IBindingList-а нужен?
у тебя же Func с IList-ом работает.

bastii

Func конечно можно переписать, но хотелось бы зависимость от IList оставить. Вариант с адапером IBindingList я не рассатриваю. Сейчас данные хранятся в BindingList, который создается BindingSource (bindingSource1.DataSource = typeof(MyType. Просто вторая идея реализовать свой IBindingList, который будет thread safe и будет пакетно слать гуи сообщения об изменении.
Оставить комментарий
Имя или ник:
Комментарий: