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

OK uri を呼び出してから待ちます

public decimal GetRateForCurrency(string fromCurrency, string 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;
}

ラベルのようなWebコントロールを設定して、これを行います

 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 ではサポートされていません。

別の方法として、そして私が行ったことは、Reactive Extensions ( ) を使用してチェーンを下にMicrosoft.Phone.Reactive渡すことです。IObservable

于 2012-08-05T12:32:29.883 に答える
0

非同期メソッドを実行すると、完了したメソッドで結果が得られます

StringDownloadCompleted

したがって、コードで async メソッドを呼び出し、すぐに常に 0 になる ExchangeRate を返します。

完成したメソッド 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 maps サンプルの拡張であり、アドレス ファインダー クラスが含まれています。それがどのように起動され、クライアントがどのように通知されるかを見てください

于 2012-08-05T12:14:38.167 に答える