2016-04-05 47 views
0

我使用Visual Studio 2015和Entity Framework 6构建MVVM Light WPF应用程序。当用户点击搜索按钮,它调用已在视图模型的构造函数中定义这样的RelayCommand执行异步搜索,返回ObservableCollection

SearchEmployeesRelayCommand = new RelayCommand(SearchEmployees); 

在视图模型的SearchEmployees方法是这样的:

private BackgroundWorker _worker; 

public void SearchEmployees() 
{ 
    _worker = new BackgroundWorker(); // use this to show busy indicator 

    var dataService = new EmployeeDataService(); 
    _worker.DoWork += (o, ea) => 
    { 
     SearchResults = dataService.SearchEmployees(SelectedColumn, SearchValue); 
    }; 
    _worker.RunWorkerCompleted += (o, ea) => 
    { 
     IsSearching = false; 
    }; 

    IsSearching = true; 
    _worker.RunWorkerAsync(); 
} 

的数据服务的搜索方法是这样的:

public ObservableCollection<EmployeeViewModel> 
    SearchEmployees(string selectedColumn, string searchValue) 
{ 
    var paramEmployee = Expression.Parameter(typeof(Employee), "e"); 

    var comparison = Expression.Lambda<Func<Employee, bool>>(
     Expression.Equal(
      Expression.Property(paramEmployee, selectedColumn), 
      Expression.Constant(searchValue)), 
      paramEmployee).Compile(); 

    using (var context = new MyEntities()) 
    { 
     var query = (from e in context.Employees 
        .Where(comparison) 
        select new EmployeeViewModel 
        { 
         // Various EF model properties... 
        }); 
     return new ObservableCollection<EmployeeViewModel>(query); 
    } 
} 

如果我尽量让上面的方法asyncawaitable,像这样的东西:

return await new ObservableCollection<EmployeeViewModel>(query); 

它给这个错误:

'ObservableCollection' does not contain a definition for 'GetAwaiter' and no extension method 'GetAwaiter' accepting a first argument of type 'ObservableCollection' could be found (are you missing a using directive or an assembly reference?)

你如何使搜索async如果它返回一个ObservableCollection?谢谢。

更新:对于忙碌的指示工作,我不得不做出这个改变:

_worker.DoWork += async (o, ea) => 
{ 
    SearchResults = await dataService 
     .SearchEmployees(selectedColumnValue, SearchValue); 
    IsSearching = false; 
}; 

我完全删除了_worker.RunWorkerCompleted块。有可能有更好的方法来做到这一点,但这是我得到它的工作原理。

+1

您需要阅读此https://msdn.microsoft.com/en-us/library/hh191443.aspx – Will

回答

2

有几种方法。首先,您可以保持数据库访问同步,并在后台线程上运行它。需要注意的是Task.Run是一个现代化的替代BackgroundWorker(我有一个blog series that draws parallels between the two):

public async Task SearchEmployeesAsync() 
{ 
    var dataService = new EmployeeDataService(); 
    var selectedColumn = SelectedColumn; 
    var searchValue = searchValue; 

    IsSearching = true; 
    try 
    { 
    SearchResults = await Task.Run(() => dataService.SearchEmployees(selectedColumn, searchValue)); 
    } 
    finally 
    { 
    IsSearching = false; 
    } 
} 

或者,因为你正在使用EF6,你可以让你的数据库查询异步,而不是浪费时间与后台线程都:

public async Task<ObservableCollection<EmployeeViewModel>> 
    SearchEmployeesAsync(string selectedColumn, string searchValue) 
{ 
    var paramEmployee = Expression.Parameter(typeof(Employee), "e"); 
    var comparison = Expression.Lambda<Func<Employee, bool>>(
    Expression.Equal(
     Expression.Property(paramEmployee, selectedColumn), 
     Expression.Constant(searchValue)), 
     paramEmployee).Compile(); 

    using (var context = new MyEntities()) 
    { 
    var query = (from e in context.Employees 
       .Where(comparison) 
       select new EmployeeViewModel 
       { 
        // Various EF model properties... 
       }); 
    var data = await query.ToListAsync(); 
    return new ObservableCollection<EmployeeViewModel>(data); 
    } 
} 

public async Task SearchEmployeesAsync() 
{ 
    var dataService = new EmployeeDataService(); 
    IsSearching = true; 
    try 
    { 
    SearchResults = await dataService.SearchEmployeesAsync(SelectedColumn, SearchValue); 
    } 
    finally 
    { 
    IsSearching = false; 
    } 
} 

您应该不是使BackgroundWorker.DoWork异步;这会导致它“提早结束”并阻止它正常处理异常。 BGW根本没有设计成与async代码一起使用。

+0

谢谢@StephenCleary。是否有一个'query.ToListAsync()'的原因,然后从那里得到一个新的'ObservableCollection'? – Alex

+0

这给了我'RelayCommand'麻烦,这是一个委托方法名称,没有返回类型。如何将其返回类型从'void'更改为'Task'这一行'SearchEmployeesRelayCommand = new RelayCommand(SearchEmployees);'? – Alex

+0

我认为这解决了'RelayCommand'返回一个值的问题:http://stackoverflow.com/questions/2240042/commanding-in-mvvm-wpf-how-to-return-a-value – Alex