Подделка синхронных звонков в Silverlight WP7 - PullRequest
8 голосов
/ 17 августа 2010

Я портирую некоторый код из полной .NET Framework на версию WP7 и сталкиваюсь с проблемой синхронных и асинхронных вызовов.

 string response;
 string requestString = GenerateReqString();
 HttpWebRequest req = (HttpWebRequest) WebRequest.Create("endpoint");
 req.Method = "POST";
 req.ContentType = "text/xml";

 req.ContentLength = requestString.Length;

 StreamWriter sw = new StreamWriter (req.GetRequestStream(), System.Text.Encoding.ASCII);
 sw.Write(requestString);
 sw.Close();

 StreamReader sr = new StreamReader(req.GetResponse().GetResponseStream());
 response = sr.ReadToEnd();
 sr.Close();

Затем строка ответа анализируется в списке объектов, возвращаемых методом.

Проблема, с которой я столкнулся, заключается в том, что в Silverlight / WP7 нет способа сделать синхронный вызов. Если я использую обратный вызов, я получу ответ в другой функции и не смогу вернуть его из исходной функции. Есть ли способ сделать синхронный вызов или вернуться из функции CallBack обратно к методу, который инициировал асинхронный вызов?

Ответы [ 4 ]

11 голосов
/ 17 августа 2010

Вы должны думать о проблеме по-другому.Чтобы асинхронные вещи «ощущались» синхронно, самый простой способ сделать это - реструктурировать ваш код, чтобы использовать ' стиль передачи продолжения '.

По сути, вместо вызова функциикоторый возвращает значение, а затем вы обрабатываете это значение, вызываете функцию, передавая ей анонимную функцию в качестве делегата.Затем вызываемая функция вызывает делегата, передавая строку.

Вот пример, в котором используются анонимные функции и лямбда-выражения:

void DoSomethingAsync( Action<string> callback ) {
    HttpWebRequest req; // TODO: build your request

    req.BeginGetResponse( result => {
        // This anonymous function is a closure and has access 
        // to the containing (or enclosing) function.
        var response = req.EndGetResponse( result );

        // Get the result string and call the callback
        string resultString = null; // TODO: read from the stream

        callback(resultString);
    }, null );
}

Это половина решения.Следующая часть, это на самом деле назвать это.Представьте, что у вас есть экземпляр ICommand или более простой, событие нажатия кнопки, которое необходимо для вызова этой функции и «получения строки».Вместо «получения строки» вы вызываете эту функцию и предоставляете метод обратного вызова (который будет закрытием).

void btnGo_Click( object sender, EventArgs e ) {
    DoSomethingAsync( resultString => {
        // This anonymous function is called when the web request has
        // finished and has your string. 

        // Now that we have the string, we can go and process it.
        ProcessWebResponseResult( resultString );
    });
}

Вот действительно хорошая статья, объясняющая эту концепцию далее: http://blogs.msdn.com/b/wesdyer/archive/2007/12/22/continuation-passing-style.aspx

2 голосов
/ 04 октября 2010

Сначала я предлагаю попробовать освоиться с асинхронностью, но если вы действительно хотите / хотите преобразовать асинхронный вызов в синхронный, вы можете использовать ManualResetEvent для достижения желаемого результата.

Вот краткий примересли использование:

public ManualResetEvent _event = new ManualResetEvent(false);

...
{
    ...
    var wc = new WebClient();
    wc.OpenReadCompleted += new OpenReadCompletedEventHandler(ReadCompleted);
    wc.OpenReadAsync(uri);

    // block until async call is complete
    _event.WaitOne();
}

private static void ReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
    ...
    // set event to unblock caller
    _event.Set();
}

Теперь ваш код будет блокироваться в строке _event.WaitOne();, пока не будет вызван _event.Set();.

Удачи!

1 голос
/ 17 августа 2010

Ознакомьтесь с библиотекой Power Threading Wintellect, которая позволяет выполнять асинхронные операции с моделью синхронного программирования.

http://csharperimage.jeremylikness.com/2010/03/sequential-asynchronous-workflows-in.html

0 голосов
/ 28 октября 2010

Лучше делать это асинхронно, чтобы пользователь мог продолжать взаимодействовать с устройством.

Я подозреваю, что причиной, по которой вы хотели это сделать, является предотвращение взаимодействия пользователя с определенными элементами управления до тех пор, пока ваш запрос не будет выполнен.

Принятый способ подойти к этому - скрыть или отключить элементы пользовательского интерфейса, с которыми не следует взаимодействовать во время обработки запроса.

...