2016-04-05 74 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