Использование Rx для геокодирования адреса в Bing Maps - PullRequest
3 голосов
/ 17 марта 2011

Я учусь использовать расширения Rx для приложения Silverlight 4, над которым я работаю. Я создал пример приложения, чтобы закрепить процесс, и я не могу заставить его что-либо вернуть. Вот основной код:

    private IObservable<Location> GetGPSCoordinates(string Address1)
    {
        var gsc = new GeocodeServiceClient("BasicHttpBinding_IGeocodeService") as IGeocodeService;

        Location returnLocation = new Location();
        GeocodeResponse gcResp = new GeocodeResponse();

        GeocodeRequest gcr = new GeocodeRequest();
        gcr.Credentials = new Credentials();
        gcr.Credentials.ApplicationId = APP_ID2;
        gcr.Query = Address1;

        var myFunc = Observable.FromAsyncPattern<GeocodeRequest, GeocodeResponse>(gsc.BeginGeocode, gsc.EndGeocode);
        gcResp = myFunc(gcr) as GeocodeResponse;

        if (gcResp.Results.Count > 0 && gcResp.Results[0].Locations.Count > 0)
        {
            returnLocation = gcResp.Results[0].Locations[0];
        }
        return returnLocation as IObservable<Location>;
    }

gcResp возвращается как ноль. Любые мысли или предложения будут с благодарностью.

Ответы [ 3 ]

1 голос
/ 17 марта 2011

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

Еще лучше, не подписывайтесь вообще и просто составьте ответ:

private IObservable<Location> GetGPSCoordinates(string Address1)
{
    IGeocodeService gsc = 
        new GeocodeServiceClient("BasicHttpBinding_IGeocodeService");

    Location returnLocation = new Location();
    GeocodeResponse gcResp  = new GeocodeResponse();

    GeocodeRequest gcr = new GeocodeRequest();
    gcr.Credentials = new Credentials();
    gcr.Credentials.ApplicationId = APP_ID2;
    gcr.Query = Address1;

    var factory = Observable.FromAsyncPattern<GeocodeRequest, GeocodeResponse>(
        gsc.BeginGeocode, gsc.EndGeocode);

    return factory(gcr)
        .Where(response => response.Results.Count > 0 && 
                           response.Results[0].Locations.Count > 0)
        .Select(response => response.Results[0].Locations[0]);
}

Если вам нужно только первое действительное значение (местоположение адреса вряд ли изменится), затем добавьте .Take(1) между Where и Select.

Редактировать: Если вы хотите специально обрабатывать адрес, не являющийсянайдено, что вы можете либо вернуть результаты и договориться с ними, либо вы можете вернуть исключение и предоставить обработчик OnError при подписке.Если вы думаете о последнем, вы должны использовать SelectMany:

return factory(gcr)
    .SelectMany(response => (response.Results.Count > 0 && 
        response.Results[0].Locations.Count > 0)
        ? Observable.Return(response.Results[0].Locations[0])
        : Observable.Throw<Location>(new AddressNotFoundException())
    );
0 голосов
/ 17 марта 2011

Ричард (и другие),

Итак, у меня есть код, возвращающий местоположение, и у меня есть подписывающий код вызова.Вот (надеюсь) последний вопрос.Когда я вызываю GetGPSCoordinates, следующий оператор выполняется немедленно, не дожидаясь окончания подписки.Вот пример в обработчике события кнопки OnClick.

Location newLoc = new Location();

GetGPSCoordinates(this.Input.Text).ObserveOnDispatcher().Subscribe(x =>
            {
             if (x.Results.Count > 0 && x.Results[0].Locations.Count > 0)
                  {
                     newLoc = x.Results[0].Locations[0];
                     Output.Text = "Latitude: " + newLoc.Latitude.ToString() +
  ", Longtude: " + newLoc.Longitude.ToString();
                  }
             else
                  {
                    Output.Text = "Invalid address";
                  }
});
            Output.Text = " Outside of subscribe --- Latitude: " + newLoc.Latitude.ToString() +
  ", Longtude: " + newLoc.Longitude.ToString();

Назначение Output.Text, имеющее место вне Subscribe, выполняется до завершения Subscribe и отображает нули, а затем тот, что в подписке, отображает новое местоположениеinfo.

Цель этого процесса - получить информацию о местоположении, которая затем будет сохранена в записи базы данных, и я последовательно обрабатываю несколько адресов в цикле Foreach.Я выбрал Rx Extensions в качестве решения, чтобы избежать проблемы асинхронного обратного вызова как ловушки кодирования.Но, похоже, я обменял одну ловушку на другую.

Мысли, комментарии, предложения?

0 голосов
/ 17 марта 2011

Если вы развернете тип myFunc, вы увидите, что это Func<GeocodeRequest, IObservable<GeocodeResponse>>.

Func<GeocodeRequest, IObservable<GeocodeResponse>> myFunc =
    Observable.FromAsyncPattern<GeocodeRequest, GeocodeResponse>
        (gsc.BeginGeocode, gsc.EndGeocode);

Поэтому, когда вы звоните myFunc(gcr), у вас есть IObservable<GeocodeResponse>, а не GeocodeResponse.Ваш код myFunc(gcr) as GeocodeResponse возвращает null, потому что приведение неверно.

Вам нужно либо получить последнее значение наблюдаемого, либо просто подписаться.Вызов .Last() заблокирует.Если вы позвоните по номеру .Subscribe(...), ваш ответ поступит через нить обратного вызова.

Попробуйте сделать следующее:

gcResp = myFunc(gcr).Last();

Дайте мне знать, как вы поступите.

...