1

我有一个方法如下:

      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。谢谢。另外,我注意到回调永远不会被调用,因为我在其中有一个断点,并且异常也没有被调用。所以我不知道问题出在哪里。感谢任何帮助。

4

5 回答 5

1

您可以使用事件等待句柄来阻塞当前线程并等待异步调用...

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 框架来确认是这种情况,但我认为是这样。

于 2012-08-05T11:57:42.983 回答
0

当您运行异步方法时,您将获得完成方法的结果,即

字符串下载完成

因此,在您的代码中,您调用异步方法并立即返回 ExchangeRate,它始终为 0。

您必须在完成的方法 StringDownloadCompleted 中获取 ExchangeRate

如果您想在 GetRateForCurrency 中获取 ExchangeRate,请进行同步调用

client.DownloadString(new Uri(_requestUri + fromCurrency + "=?" + toCurrency));
于 2012-08-05T11:57:33.447 回答
0

这是你需要做的。

你在课堂上创建一个事件。在您的代码中,您触发异步 Web 客户端调用。调用完成后,您将包装数据并设置事件。我倾向于定义可以保存数据的事件参数。

设置事件后,调用者将收到通知。

如果您想要一个示例,请查看我的帖子中的源代码 http://invokeit.wordpress.com/2012/06/30/bing-mapcontrol-offline-tiles-solution-wpdev-wp7dev/

它是 bing 地图示例的扩展,它包含地址查找器类。看看它是如何被解雇的以及如何通知客户的

于 2012-08-05T12:14:38.167 回答
0

好的,在呼叫 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();
}
于 2012-08-05T12:29:00.190 回答
0

您在这里唯一的选择GetRateForCurrency也是异步(这意味着引发自己的Completed事件)。

是否支持 TPL,您可以Task<T>用作将异步包装到链中的好方法,但不幸的是 WP7 不支持它。

作为一种替代方法,我所做的是使用响应式Microsoft.Phone.Reactive扩展IObservable

于 2012-08-05T12:32:29.883 回答