ToListAsync冻结UI

时间:2015-02-19 01:35:26

标签: wpf entity-framework async-await

我有一个名为Patient的模型:

[Key]
public Guid Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }

我的存储库返回所有患者(行数为1):

public async Task<List<Patient>> GetPatientsAsync()
{
    //await Task.Delay(1).ConfigureAwait(false);
    return await _context.Patients.ToListAsync();
}

运行该代码会冻结UI,但如果我删除GetPatientsAsync()中的注释,则UI会在返回所有患者(同样只返回1行)时响应。

在我的ViewModel端,我这样称呼它:

public async Task LoadPatients()
{
      var s = await _repository.GetPatientsAsync();
      //if (Patients != null) SelectedPatient = Patients.FirstOrDefault();
}

任何线索,为什么会这样?

由于

2 个答案:

答案 0 :(得分:0)

所以我解决了这个问题,我正在使用CallMethodOnLoadBehaviour.cs。由于此行为未作为await Task执行,因此它阻止了UI。

我需要做的就是调用存储库GetPatientsAsync我在Task.Run(() => _repository.GetPatientsAsync());内部。

如果有更好的方法可以使用反射并且能够拨打await <Task>,请告诉我们!

public class CallMethodOnLoadBehavior : Behavior<FrameworkElement>
{
    #region Properties
    public string MethodName
    {
        get { return (string)GetValue(MethodNameProperty); }
        set { SetValue(MethodNameProperty, value); }
    }

    // Using a DependencyProperty as the backing store for MethodName.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty MethodNameProperty =
        DependencyProperty.Register("MethodName", typeof(string), typeof(CallMethodOnLoadBehavior), new PropertyMetadata(null));

    public object TargetObject
    {
        get { return GetValue(TargetObjectProperty); }
        set { SetValue(TargetObjectProperty, value); }
    }

    // Using a DependencyProperty as the backing store for TargetObject.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty TargetObjectProperty =
        DependencyProperty.Register("TargetObject", typeof(object), typeof(CallMethodOnLoadBehavior), new PropertyMetadata(null));
    #endregion

    #region Methods
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.Loaded += OnLoaded;
    }

    private void OnLoaded(object sender, RoutedEventArgs e)
    {
        if (AssociatedObject == null || string.IsNullOrWhiteSpace(MethodName) || TargetObject == null) return;
        var minfo = TargetObject.GetType().GetTypeInfo().GetDeclaredMethod(MethodName);
        if (minfo == null) return;
        minfo.Invoke(TargetObject, null);
    }
    #endregion
}

答案 1 :(得分:0)

您可以尝试将您的属性分配封送回UI线程。我不确定EF的工作原理。我的直觉告诉我ToListAsync()是延迟加载的,这意味着当你调用FirstOrDefault()时,返回的值仍然是从后台线程获取的(因为你等待存储库中的调用)并且你尝试分配和调用主线程OnPropertyChanged

public async Task LoadPatients()
{
      var s = await _repository.GetPatientsAsync();
      if (Patients != null) 
      {
          var patient = Patients.FirstOrDefault();
          Application.Dispatcher.Current.Invoke(() => SelectedPatient = patient);
      }
}