- Вы не можете заблокировать основной поток Silverlight, иначе ваш пользовательский интерфейс зависнет. Это причина того, что все сетевые операции в SL принудительно асинхронны.
- Вы не можете касаться пользовательского интерфейса из любого потока, кроме потока пользовательского интерфейса.
Это два ограничения. Я бы подошел к этому, чтобы создать функцию «асинхронной обертки», чтобы обернуть ее для вас. Это займет 3 функции (делегаты):
1. Выполнить в новом потоке ("f") (убедитесь, что вы не захватываете объекты пользовательского интерфейса в своей функции!)
2. Выполнить в порядке исключения («econt»)
3. Выполнить по полной («продолжение»)
Оба продолжения будут отправлены в потоке пользовательского интерфейса через System.Windows.Deployment.Current.Dispatcher.BeginInvoke.
При этом вам просто нужно изменить вызовы веб-службы на «синхронизацию через асинхронный», как говорит mbeckish (используйте ManualResetEvent, WaitOne из потока синхронизации, Set on callback).
Код для помощника может выглядеть примерно так (psuedocode, не проверял):
static void AsyncHelp<T>(Func<T> f, Action<Exception> econt, Action<T> cont) {
var t = new Thread((_) => {
try {
var res = f();
System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() => cont(res));
} catch (Exception ex) {
System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() => econt(ex));
}
});
t.Start();
}
Вы бы в конечном итоге использовали это так:
some_handler() {
var id = mytextbox.Text; // Save from UI to local
AsyncHelp(
() => GetBla(id),
bla => result.Text = bla.ToString(), // This is safe cause it's dispatched
ex => error.Text = ex.ToString()
);
}
Обновление
Чтобы выполнить синхронизацию через асинхронный вызов, вы должны сделать что-то вроде этого, предполагая, что вы используете «Асинхронный шаблон на основе событий» по умолчанию (использовать BeginXXX / EndXXX проще, IMO).
Exception ex;
Result r;
var mre = new ManualResetEvent(false);
myService.OnGetBlaCompleted += (_, e) => {
ex = e.Error;
r = e.Result;
mre.Set();
}
myService.GetBlaAsync(id);
mre.WaitOne();
if (ex != null) throw ex;
// and so on