簡體   English   中英

我該如何處理Windows Phone WebClient異步問題?

[英]How do I deal with this windows phone webclient asynchronous issue?

我有如下方法:

      public decimal GetExchangeRate(string fromCurrency, string toCurrency)
      {
            GoogleCurrencyService googleCurrencyService = new GoogleCurrencyService();
            return googleCurrencyService.GetRateForCurrency(fromCurrency, toCurrency);

      } 

和另一類如下

public class GoogleCurrencyService
{
    public decimal GetRateForCurrency(string fromCurrency, string toCurrency)
    {

        try
        {
            WebClient client = new WebClient();
            client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(StringDownloadCompleted);
            client.DownloadStringAsync(new Uri(_requestUri + fromCurrency + "=?" + toCurrency));

        }
        catch (Exception)
        {
            ExchangeRate = 0;
        }

        return ExchangeRate;
    }

    private void StringDownloadCompleted(object sender, DownloadStringCompletedEventArgs e)
    {
        _response = e.Result;
        ExchangeRate = ParseResponseAndGetExchangeRate();
    }

}//class GoogleCurrencyService

變量ExchangeRate始終為零,因此我相信函數調用“ GetRateForCurrency”會在調用異步回調之前返回。 我如何確保不會發生這種情況,因為我需要在返回之前設置變量ExchangeRate。 謝謝。 另外,我注意到回調從未被調用過,因為我在其中有一個斷點,而且也沒有調用異常。 因此,我不知道問題出在哪里。任何幫助表示贊賞。

您可以使用事件等待句柄來阻止當前線程並等待異步調用...

public class GoogleCurrencyService
{
    private const string RequestUri = "http://www.google.com/ig/calculator?hl=en&q=1{0}%3D%3F{1}";

    public decimal ExchangeRate { get; private set; }

    public decimal GetRateForCurrency(string fromCurrency, string toCurrency)
    {
        ExchangeRate = 0;
        // use a signaler to block this thread and wait for the async call.
        var signaler = new ManualResetEvent(false);
        try
        {
            var client = new WebClient();
            client.DownloadStringCompleted += StringDownloadCompleted;
            // pass the signaler as user token
            client.DownloadStringAsync(new Uri(String.Format(RequestUri, fromCurrency, toCurrency)), signaler);

            // wait for signal, it will be set by StringDownloadCompleted
            signaler.WaitOne();
        }
        finally
        {
            signaler.Dispose();
        }

        return ExchangeRate;
    }

    private void StringDownloadCompleted(object sender, DownloadStringCompletedEventArgs e)
    {
        try
        {
            ExchangeRate = ParseResponseAndGetExchangeRate(e.Result);
        }
        finally
        {
            // set signal
            ((ManualResetEvent)e.UserState).Set();
        }
    }

    private decimal ParseResponseAndGetExchangeRate(string result)
    {
        return 123;
    }
}

編輯:使用異步模式的同一類

public class GoogleCurrencyService
{
    private const string RequestUri = "http://www.google.com/ig/calculator?hl=en&q=1{0}%3D%3F{1}";

    public void GetRateForCurrency(string fromCurrency, string toCurrency, Action<decimal> callback)
    {
        var client = new WebClient();
        client.DownloadStringCompleted += StringDownloadCompleted;
        // pass the callback as user token
        client.DownloadStringAsync(new Uri(String.Format(RequestUri, fromCurrency, toCurrency)), callback);
    }

    private void StringDownloadCompleted(object sender, DownloadStringCompletedEventArgs e)
    {
        // parse response to get the rate value
        var rate = ParseResponseAndGetExchangeRate(e.Result);

        // if a callback was specified, call it passing the rate.
        var callback = (Action<decimal>)e.UserState;
        if (callback != null)
            callback(rate);
    }

    private decimal ParseResponseAndGetExchangeRate(string result)
    {
        return 123;
    }
}

消耗異步類:

// this is your UI form/control/whatever
public class MyUI
{
    public void OnButtonToGetRateClick()
    {
        var from = "USD"; // or read from textbox...
        var to = "EUR";

        // call the rate service
        var service = new GoogleCurrencyService();
        service.GetRateForCurrency(from, to, (rate) =>
            {
                // do stuff here to update UI.
                // like update ui.
            });
    }
}

也許您必須將UI更改分派到ui線程。 我這里沒有WP框架來確認確實如此,但我認為是這樣。

當您運行異步方法時,您將獲得完整方法的結果,即

StringDownloadCompleted

因此,在您的代碼中調用異步方法並立即返回ExchangeRate,該值始終為0。

您必須在完成的方法StringDownloadCompleted中獲取ExchangeRate

如果要在GetRateForCurrency中獲取ExchangeRate,請進行同步調用

client.DownloadString(new Uri(_requestUri + fromCurrency + "=?" + toCurrency));

這是您需要做的。

您可以在課堂上創建一個事件。 在您的代碼中,您將觸發異步Web客戶端調用。 調用完成后,您將包裝數據並設置事件。 我傾向於定義可以保存數據的事件args。

設置事件后,呼叫者將收到通知。

如果您想舉個例子,請看一下我的帖子中的資源http://invokeit.wordpress.com/2012/06/30/bing-mapcontrol-offline-tiles-solution-wpdev-wp7dev/

它是bing映射示例的擴展,並且包含地址查找器類。 看一下它是如何觸發的以及如何通知客戶

好的,等到uri后再打電話

公共十進制GetRateForCurrency(字符串fromCurrency,字符串toCurrency){

    try
    {
        WebClient client = new WebClient();
        client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(StringDownloadCompleted);
        client.DownloadStringAsync(new Uri(_requestUri + fromCurrency + "=?" + toCurrency));
        Thread.sleep(500000); //waiting
    }
    catch (Exception)
    {
        ExchangeRate = 0;
    }

    return ExchangeRate;
}

所以設置像標簽這樣的webcontrol並執行此操作

 private void StringDownloadCompleted(object sender, DownloadStringCompletedEventArgs e)
{
    _response = e.Result;
    yourlabel.Text = _response ;
    ExchangeRate = ParseResponseAndGetExchangeRate();
}

您在此處的唯一選擇也是使GetRateForCurrency異步(這意味着引發其自己的Completed事件)。

如果TPL被支持,您可以使用Task<T>作為將異步包裹起來的一種好方法,但是不幸的是WP7不支持它。

作為一種替代方法,我所做的是使用Reactive Extensions( Microsoft.Phone.Reactive )並將IObservable到鏈下-但是,如果您僅打算將Rx用於以下目的,則Rx有很多東西要學習這一情況。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM