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 的构造函数中初始化它,所以为了测试目的,我把它放在 OnNavigateTo 中,但是如果有办法做到这一点,请让我知道,因为我觉得它会更有意义,不是吗?

谢谢。

4

2 回答 2

1

.Result调用导致死锁,因为当您等待 UI 线程上的结果时,GetMyLocation 方法希望同时继续在 UI 线程上运行。

为了解决这个问题,只需将 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 回答