0

ViewModel から GetGeopositionAsync を呼び出すとハングするのに、ビューから呼び出すと正常に動作する理由について完全に混乱しているので、誰かが私をここで正しい方向に向けることができますか?

動作するコードは次のとおりです。

private async void btnLocate_Click(object sender, RoutedEventArgs e)
{
    if (this._geolocator.LocationStatus != PositionStatus.Disabled && this._geolocator.LocationStatus != PositionStatus.NotAvailable)
    {
        try
        {
            this._geolocator.DesiredAccuracyInMeters = 5;
            Geoposition position = await this._geolocator.GetGeopositionAsync();
            Geocoordinate geocoordinate = position.Coordinate;
            this.mapWithMyLocation.Center = CoordinateConverter.ConvertGeocoordinate(geocoordinate);
        }
        catch (System.UnauthorizedAccessException)
        {
            throw;
        }
        catch (TaskCanceledException)
        {
            throw;
        }
        catch (Exception)
        {
            throw;
        }
    }
}

動作しないコードは次のとおりです。

public class LocationEntryViewModel : BaseViewModel
{
    async public Task<GeoCoordinate> GetMyLocation()
    {
        if (this._geolocator.LocationStatus != PositionStatus.Disabled && this._geolocator.LocationStatus != PositionStatus.NotAvailable)
        {
            try
            {
                this._geolocator.DesiredAccuracyInMeters = 5;
                Geoposition position = await this._geolocator.GetGeopositionAsync();                    
                Geocoordinate geocoordinate = position.Coordinate;
                return CoordinateConverter.ConvertGeocoordinate(geocoordinate);
            }
            catch (System.UnauthorizedAccessException)
            {
                throw;
            }
            catch (TaskCanceledException)
            {
                throw;
            }
            catch (Exception)
            {
                throw;
            }
        }
        else
        {
            return new GeoCoordinate();
        }
    }

    public void SetMyLocation()
    {
        this.MyLocation = GetMyLocation().Result;
    }
}

そして、私は自分のビューからこれを呼び出します

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
        _locationEntryViewModel.SetMyLocation();
    }

ViewModel のコンストラクターからこれを初期化するべきではないという記事を読んだことがありますが、これを ViewModel のコンストラクターから初期化するべきではありません。私はそれがより理にかなっていると感じているので知っていますよね??

ありがとう。

4

2 に答える 2

1

UI スレッドで結果を待っているときに、 GetMyLocationメソッドが同時に UI スレッドで実行を継続しようとするため、.Result 呼び出しがデッドロックを引き起こしています 。

これを解決するには、SetMyLocation メソッドを非同期に変更し、次のように使用します。

public async Task SetMyLocation()
{
    this.MyLocation = await GetMyLocation();
}

また、SetMyLocation を呼び出している場所でも、await を使用します。

于 2013-11-10T12:22:49.513 に答える
0

あなたの問題はResult、UI スレッドで呼び出しているため、ブログで完全に説明しているデッドロックを引き起こしていることです。

これを修正するにはNotifyTaskCompletion、私の AsyncEx ライブラリの型のような型を使用して、タスクの完了時にプロパティ変更イベントを提供する必要があります。コンストラクターでこの種の初期化を開始しても問題ありません。

public class LocationEntryViewModel : BaseViewModel
{
  public INotifyTaskCompletion<GeoCoordinate> MyLocation { get; private set; }

  public LocationEntryViewModel()
  {
    MyLocation = NotifyTaskCompletion.Create(GetMyLocation());
  }
}

次に、データバインディングで のようなパスを使用できますMyLocation.Result。これは完了nullするまでであることに注意してください。GetMyLocation別の UI (スピナーなど) が必要な場合は、 にデータ バインドできますMyLocation.IsCompleted。また、例外をデータバインドする場合は、MyLocation.ErrorMessage. その他便利な物件をご用意しております。

詳細については、asyncプロパティのブログ投稿を参照してください。

于 2013-11-10T01:36:26.977 に答える