Портативный эквивалент библиотеки классов диспетчера.Вызов или Диспетчер.Функции runasync
В .NET, Windows 8 и Windows Phone 7 у меня есть код, подобный этому:
public static void InvokeIfRequired(this Dispatcher dispatcher, Action action)
{
if (dispatcher.CheckAccess())
{
action();
}
else
{
dispatcher.Invoke(action);
}
}
Как бы я сделал что-то в переносимой библиотеке классов? Было бы неплохо иметь одну платформу агностической реализации этого. Моя идея состоит в том, чтобы использовать TPL, который не доступен в WP7, но определенно будет скоро.
// PortableDispatcher must be created on the UI thread and then made accessible
// maybe as a property in my ViewModel base class.
public class PortableDispatcher
{
private TaskScheduler taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
public void Invoke(Action action)
{
if (Alread on UI thread. How would I do this.)
{
action();
}
Task.Factory.StartNew(
action,
CancellationToken.None,
TaskCreationOptions.None,
taskScheduler);
}
}
Единственное, в чем я не уверен, так это в том, каковы будут последствия этого для производительности. Возможно, я сделаю несколько тестов.2 ответа:
Вы можете использовать SynchronizationContext.Post или метод отправки. Он переносим, и при использовании платформы пользовательского интерфейса с диспетчером текущий контекст синхронизации делегирует работу диспетчеру.
В частности, вы можете использовать следующий код:
void InvokeIfRequired(this SynchroniationContext context, Action action) { if (SynchroniationContext.Current == context) { action(); } else { context.Send(action) // send = synchronously // context.Post(action) - post is asynchronous. } }
С появлением TPL. Я придумал немного улучшенную версию принятого ответа, которая возвращает задачу и может быть ожидаема с помощью новых ключевых слов async и await.
public Task RunAsync(Action action) { TaskCompletionSource<object> taskCompletionSource = new TaskCompletionSource<object>(); if (this.synchronizationContext == SynchronizationContext.Current) { try { action(); taskCompletionSource.SetResult(null); } catch (Exception exception) { taskCompletionSource.SetException(exception); } } else { // Run the action asyncronously. The Send method can be used to run syncronously. this.synchronizationContext.Post( (obj) => { try { action(); taskCompletionSource.SetResult(null); } catch (Exception exception) { taskCompletionSource.SetException(exception); } }, null); } return taskCompletionSource.Task; }