обновление пользовательского интерфейса из потока в winrt

<p>так как предварительный просмотр потребительской версии windows 8 был выпущен несколько дней назад, я работаю над новым winrt (для приложений metro) в c #, и я перенес свой самописанный класс irc на новую многопоточность и работу в сети.</p><p>проблема заключается в следующем: мой класс выполняет поток для получения сообщений с сервера. если это происходит, поток выполняет некоторый анализ, а затем запускает событие, чтобы сообщить об этом приложению. подписанная функция затем "должна" обновить пользовательский интерфейс (текстовый блок).</p><p>это проблема, поток не может обновить пользовательский интерфейс, и метод invoker, который работал с .net 4.0, кажется, больше невозможен. есть ли новый обходной путь для этого или даже лучший способ обновить пользовательский интерфейс? если я попытаюсь обновить пользовательский интерфейс от подписчика события, я получу это <code>exception</code>:</p><blockquote> <p>приложение вызвало интерфейс, который был назначен для другого потока (исключение из hresult: 0x8001010e (rpc\_e\_wrong\_thread))</p> </blockquote>

<p>предпочтительным способом решения этой проблемы в winrt (и c # 5 в целом) является использование <code>async</code>-<code>await</code>:</p><pre><code>private async void button\_click(object sender, routedeventargs e) { string text = await task.run(() => compute()); this.textblock.text = text; } </code></pre><p>здесь метод <code>compute()</code> будет выполняться в фоновом потоке, а когда он завершится, остальная часть метода будет выполняться в потоке пользовательского интерфейса. в то же время поток пользовательского интерфейса может делать все, что ему нужно (например, обрабатывать другие события).</p><p>но если вы не хотите или не можете использовать <code>async</code>, вы можете использовать <code>dispatcher</code> аналогичным (хотя и другим) способом, как в wpf:</p><pre><code>private void button\_click(object sender, routedeventargs e) { task.run(() => compute()); } private void compute() { // perform computation here dispatcher.invoke(coredispatcherpriority.normal, showtext, this, resultstring); } private void showtext(object sender, invokedhandlerargs e) { this.textblock.text = (string)e.context; } </code></pre>

<p>вот простой способ сделать это, я думаю!</p><p>сначала запишите ваш интерфейс syncronizationcontext с помощью следующего:</p><pre><code> var uisynccontext = taskscheduler.fromcurrentsynchronizationcontext(); </code></pre><p>запустите операцию вызова сервера или любую другую операцию фонового потока, которая вам нужна:</p><pre><code> task servertask= task.run(()=> { /* doworkhere(); */} ); </code></pre><p>затем выполните операцию пользовательского интерфейса над uisynccontext, который вы записали на первом шаге:</p><pre><code> task uitask= servertask.continuewith((t)=>{textblockname.text="your value"; }, uisynccontext); </code></pre>

<p>имо я думаю, что "threadpool" является рекомендуемым маршрутом.</p><p> <a href="https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh465290.aspx">https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh465290.aspx</a> </p><pre><code>public static task invokebackground(func<task> action) { var tcs = new taskcompletionsource<bool>(); var unused = threadpool.runasync(async (obj) => { await action(); tcs.trysetresult(true); }); return tcs.task; } </code></pre>