SynchronizationContext.Метод Post to UI
Я работаю с веб-службами, поэтому мне необходимо увеличить длину сеанса / снова подключиться и получить большие наборы данных и т. д. Иногда это может быть длительным, поэтому я хотел его в отдельном потоке, который обновляет пользовательский интерфейс асинхронно.
кажется, я не могу заставить свою голову использовать synchronizationContext для вызова метода в моем потоке пользовательского интерфейса. У меня есть это, благодаря чему я передал свой контекст UIThread в свой поток, и теперь я хочу обновить некоторые метки и т. д. В потоке UI. Я читал тонн сообщения, но никто не объясняет, как просто передать некоторые параметры обратно в метод, или, может быть, они делают, но я слишком устал/глуп, чтобы видеть это.
/ / на основной поток пользовательского интерфейса
public void updateConnStatus(string conn_name, bool connected)
{
switch (conn_name)
{
case "Conn" : if (connected == true){ //do something} break;
//в отдельном потоке
uiContext.Post( //something to do with delegates in here that eludes me );
если бы кто-то мог просто объяснить, как я связываю sendOrPostCallBack с оригинальным методом, я был бы очень благодарен.
спасибо
Edit:
мне удалось получить код для запуска и попытаться запустить событие, это заполняет мои пользовательские eventArgs хорошо, но либо его высказывание, что updateUIConnStatus не был создан, нуждается в дополнительном исследовании :o
public void updateUIThread(string conn, bool connected)
{
uiContext.Post(new SendOrPostCallback((o) => { updateConnStatus(this, new MyEventArgs<String, Boolean>(conn, connected)); }), null);
}
public class MyEventArgs<T, U> : EventArgs
{
private T _val1; private U _val2;
public MyEventArgs(T value1, U value2) { _val1 = value1; _val2 = value2; }
public T val1 { get { return _val1;} }
public U val2 { get {return _val2;} }
}
public event EventHandler<MyEventArgs<String, Boolean>> updateConnStatus = Delegate {};
/ / на UI Thread сейчас
public void updateConnStatus(object sender, MyEventArgs<String,Boolean> e)
{
switch (e.val1)
{
case "Conn1" :
if (e.val2 == true)
{
2 ответов
вам нужен делегат типа SendOrPostCallback. Что довольно неудобно, требуется только один аргумент типа объект. Вы определенно должны посмотреть на класс Task, доступный в .NET 4, чтобы сделать это проще. Или используйте лямбду, например:
string conn_name = "foo";
uiContext.Post(new SendOrPostCallback((o) => {
updateConnStatus(conn_name, true);
}), null);
код между {фигурными скобками } выполняется в потоке пользовательского интерфейса.
обычно вы создаете экземпляры своих типов (например, ViewModels) в потоке пользовательского интерфейса, поэтому вы можете просто сохранить SynchronizationContext или TaskScheduler (предпочтительный IMHO) в частном поле, а затем сравнить его при необходимости...
private readonly SynchronizationContext _syncContext = SynchronizationContext.Current;
private readonly TaskScheduler _scheduler = TaskScheduler.Current;
void OnSomeEvent(object sender, EventArgs e)
{
if (_syncContext != SynchronizationContext.Current)
{
// Use Send if you need to get something done as soon as possible.
// We'll be polite by using Post to wait our turn in the queue.
_syncContext.Post(o => DoSomething(), null);
return;
}
// Call directly if we are already on the UI thread
DoSomething();
}
void OnSomeOtherEvent(object sender, MyEventArgs e)
{
var arg1 = e.Arg1; // "Hello "
var arg2 = e.Arg2; // {"World", "!"};
// Process args in the background, and then show the result to the user...
// NOTE: We don't even need to check the context because we are passing
// the appropriate scheduler to the continuation that shows a MessageBox.
Task<string>.Factory.StartNew(() => ReturnSomething(arg1, arg2))
.ContinueWith(t => MessageBox.Show(t.Result), _scheduler);
}
void DoSomething() { MessageBox.Show("Hello World!"); }
string ReturnSomething(string s, IEnumerable<string> list)
{
return s + list.Aggregate((c, n) => c + n);
}