Как зайти в Даркнет?!
25th January, 01:11
6
0
Как в tkinter из поля ввода Entry получить значение в одну переменную и обновить строку кнопкой, затем получить ещё одно введённое значение и затем сложить их. Ниже пример кода
21st July, 19:00
894
0
Программа, которая создает фейковые сервера в поиске игровых серверов CS 1.6 Steam
21st March, 17:43
948
0
Очень долго работает Update запрос Oracle
27th January, 09:58
914
0
не могу запустить сервер на tomcat HTTP Status 404 – Not Found
21st January, 18:02
905
0
Где можно найти фрилансера для выполнения поступающих задач, на постоянной основе?
2nd December, 09:48
938
0
Разработка мобильной кроссплатформенной военной игры
16th July, 17:57
1724
0
период по дням
25th October, 10:44
3955
0
Пишу скрипты для BAS только на запросах
16th September, 02:42
3720
0
Некорректный скрипт для закрытия блока
14th April, 18:33
4613
0
прокидывать exception в блоках try-catch JAVA
11th March, 21:11
4381
0
Помогите пожалуйста решить задачи
24th November, 23:53
6086
0
Не понимаю почему не открывается детальное описание продукта
11th November, 11:51
4350
0
Нужно решить задачу по программированию на массивы
27th October, 18:01
4396
0
Метода Крамера С++
23rd October, 11:55
4309
0
помогите решить задачу на C++
22nd October, 17:31
4002
0
Помогите решить задачу на python с codeforces
22nd October, 11:11
4492
0
Python с нуля: полное руководство для начинающих
18th June, 13:58
2599
0
Самый чистый способ вызова событий перекрестного потока
Я нахожу, что модель событий .NET такова, что я часто вызываю событие в одном потоке и слушаю его в другом потоке. Мне было интересно, какой самый чистый способ маршалировать событие из фонового потока в мой поток UI.
Основываясь на предложениях сообщества, я использовал это:
// earlier in the code
mCoolObject.CoolEvent+=
new CoolObjectEventHandler(mCoolObject_CoolEvent);
// then
private void mCoolObject_CoolEvent(object sender, CoolObjectEventArgs args)
{
if (InvokeRequired)
{
CoolObjectEventHandler cb =
new CoolObjectEventHandler(
mCoolObject_CoolEvent);
Invoke(cb, new object[] { sender, args });
return;
}
// do the dirty work of my method here
}
У меня есть код для этого в интернете. Это гораздо лучше, чем другие предложения; определенно проверьте это.
Пример использования:
private void mCoolObject_CoolEvent(object sender, CoolObjectEventArgs args)
{
// You could use "() =>" in place of "delegate"; it's a style choice.
this.Invoke(delegate
{
// Do the dirty work of my method here.
});
}
Несколько наблюдений:
- Не создавайте простые делегаты явно в таком коде, если только вы не являетесь pre-2.0, чтобы вы могли использовать:
BeginInvoke(new EventHandler<CoolObjectEventArgs>(mCoolObject_CoolEvent),
sender,
args);
Кроме того, вам не нужно создавать и заполнять массив объектов, потому что параметр args имеет тип "params", поэтому вы можете просто передать его в списке.
Я бы, вероятно, предпочел
InvokeвместоBeginInvoke, поскольку последнее приведет к асинхронному вызову кода, который может быть или не быть тем, что вы ищете, но затруднит обработку последующих исключений без вызоваEndInvoke. Что произойдет, так это то, что ваше приложение в конечном итоге получитTargetInvocationExceptionвместо этого.
Я избегаю избыточных деклараций делегатов.
private void mCoolObject_CoolEvent(object sender, CoolObjectEventArgs args)
{
if (InvokeRequired)
{
Invoke(new Action<object, CoolObjectEventArgs>(mCoolObject_CoolEvent), sender, args);
return;
}
// do the dirty work of my method here
}
Для не-событий можно использовать делегат System.Windows.Forms.MethodInvoker или System.Action .
EDIT: кроме того, каждое событие имеет соответствующий делегат EventHandler , поэтому нет никакой необходимости повторно объявлять его.
Я сделал следующий класс 'universal' cross thread call для своей собственной цели, но я думаю, что стоит поделиться им:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
namespace CrossThreadCalls
{
public static class clsCrossThreadCalls
{
private delegate void SetAnyPropertyCallBack(Control c, string Property, object Value);
public static void SetAnyProperty(Control c, string Property, object Value)
{
if (c.GetType().GetProperty(Property) != null)
{
//The given property exists
if (c.InvokeRequired)
{
SetAnyPropertyCallBack d = new SetAnyPropertyCallBack(SetAnyProperty);
c.BeginInvoke(d, c, Property, Value);
}
else
{
c.GetType().GetProperty(Property).SetValue(c, Value, null);
}
}
}
private delegate void SetTextPropertyCallBack(Control c, string Value);
public static void SetTextProperty(Control c, string Value)
{
if (c.InvokeRequired)
{
SetTextPropertyCallBack d = new SetTextPropertyCallBack(SetTextProperty);
c.BeginInvoke(d, c, Value);
}
else
{
c.Text = Value;
}
}
}
И вы можете просто использовать SetAnyProperty() из другого потока:
CrossThreadCalls.clsCrossThreadCalls.SetAnyProperty(lb_Speed, "Text", KvaserCanReader.GetSpeed.ToString());
В этом примере приведенный выше класс KvaserCanReader запускает свой собственный поток и выполняет вызов для установки свойства text метки lb_Speed в главной форме.
Используйте контекст синхронизации, если вы хотите отправить результат в поток UI. Мне нужно было изменить приоритет потока, поэтому я отказался от использования потоков пула потоков (закомментированный код) и создал новый собственный поток. Я все еще мог использовать контекст синхронизации, чтобы вернуть, удалось ли отменить отмену базы данных или нет.
#region SyncContextCancel
private SynchronizationContext _syncContextCancel;
/// <summary>
/// Gets the synchronization context used for UI-related operations.
/// </summary>
/// <value>The synchronization context.</value>
protected SynchronizationContext SyncContextCancel
{
get { return _syncContextCancel; }
}
#endregion //SyncContextCancel
public void CancelCurrentDbCommand()
{
_syncContextCancel = SynchronizationContext.Current;
//ThreadPool.QueueUserWorkItem(CancelWork, null);
Thread worker = new Thread(new ThreadStart(CancelWork));
worker.Priority = ThreadPriority.Highest;
worker.Start();
}
SQLiteConnection _connection;
private void CancelWork()//object state
{
bool success = false;
try
{
if (_connection != null)
{
log.Debug("call cancel");
_connection.Cancel();
log.Debug("cancel complete");
_connection.Close();
log.Debug("close complete");
success = true;
log.Debug("long running query cancelled" + DateTime.Now.ToLongTimeString());
}
}
catch (Exception ex)
{
log.Error(ex.Message, ex);
}
SyncContextCancel.Send(CancelCompleted, new object[] { success });
}
public void CancelCompleted(object state)
{
object[] args = (object[])state;
bool success = (bool)args[0];
if (success)
{
log.Debug("long running query cancelled" + DateTime.Now.ToLongTimeString());
}
}
Вы можете попробовать разработать какой-то универсальный компонент, который принимает SynchronizationContext в качестве входных данных и использует его для вызова событий.