I'm using Visual Studio 2015 and Entity Framework 6 to build an MVVM Light WPF app. When the user clicks the Search button, it calls a RelayCommand
which has been defined like this in the View Model's constructor:
SearchEmployeesRelayCommand = new RelayCommand(SearchEmployees);
The SearchEmployees
method in the View Model looks like this:
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();
}
The data service's search method looks like this:
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);
}
}
If I try to make the above method async
and awaitable
, with something like this:
return await new ObservableCollection<EmployeeViewModel>(query);
It gives this error:
'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?)
How do you make the search async
if it's returning an ObservableCollection
? Thanks.
Update : For the busy indicator to work, I had to make this change:
_worker.DoWork += async (o, ea) =>
{
SearchResults = await dataService
.SearchEmployees(selectedColumnValue, SearchValue);
IsSearching = false;
};
And I removed the _worker.RunWorkerCompleted
block altogether. There probably is a better way to do that, but this was how I got it working.
There are a couple of approaches. First, you can keep your database access synchronous and just run it on a background thread. Note that Task.Run
is a modern replacement for BackgroundWorker
(I have a 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;
}
}
Alternatively, since you are using EF6, you can make your database query asynchronous and not mess around with background threads at all:
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;
}
}
You should not make BackgroundWorker.DoWork
asynchronous; that will cause it to "end early" and prevent it from gracefully handling exceptions. BGW simply wasn't designed to work with async
code.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.