В первой части я рассказал, как использовать EF 5.0 для задачи сканирования БД с целью выявления новых заданий. Однако в WPF такой подход в чистом виде применять нельзя из-за того, что задача сканирования базы данных должна постоянно выполняться в программе, а также она может занимать значительный промежуток времени. Это значит, что при синхронном ее выполнении в UI потоке, наше приложение практически постоянно будет находиться в режиме зависания, а это недопустимо. Решение этой задачи состоит в асинхронном выполнении задачи сканирования БД, с последующим выводом результатов в UI thread, так как только через UI thread мы можем менять состояние GUI. Программных реализаций такого решения много, тут я покажу использование асинхронной модели на основе задач (TAP) (.net framework 4.5) в сочетании с возможностями C# 5.0.
Асинхронный метод должен возвращать объект Task, Task<TResult>, или void. Хотя возвращать void рекомендуется только для обработчиков событий.
Перейдем непосредственно к программной реализации. Перед тем как запустить метод асинхронного сканирования БД, при первом запуске программы необходимо получить максимальный идентификатор записи в БД.
private void Application_Startup(object sender, StartupEventArgs e)
{
var mainWindow = new MainWindow();
Current.MainWindow = mainWindow;
var viewModel = new MainViewModel(mainWindow);
mainWindow.DataContext = viewModel;
mainWindow.Tb = (TaskbarIcon)FindResource("NotifIcon");
if (mainWindow.Tb != null)
mainWindow.Tb.DataContext = viewModel;
//var trayToolTip = new UserControl1 {DataContext = viewModel};
viewModel.GetId(); // получаем максимальный ID
mainWindow.Show();
}
public class MainViewModel : ViewModelBase
{
public void GetId()
{
using (var context = new CCYCEntities())
{
LastEngineId = DataService.GetLastEngId(context).ToString(CultureInfo.InvariantCulture);
}
}
class DataService
{
internal static long GetLastEngId(CCYCEntities context)
{
var tmp =
(from eng in context.Engines orderby eng.ID_Engine select eng.ID_Engine).ToList().LastOrDefault();
return tmp;
}
}
После этого в классе DataService реализуем асинхронное сканирование БД:
class DataService
{
internal static Task'<'List'<'Engine'>''>' GetNewEnginesAsync( CCYCEntities context, long maxId, CancellationToken cancellationToken)
{
return Task.Run(() =>
{
cancellationToken.ThrowIfCancellationRequested();
var tmp = (from d in context.Engines where d.ID_Engine > maxId select d).ToList();
return tmp;
});
}
}
Использование в MainViewModel:
private async void Test()
{
var ctn = new CancellationToken();
using (var context = new CCYCEntities())
{
try
{
while (true)
{
var rez = await DataService.GetNewEnginesAsync(context,_lastId,ctn);
await Task.Delay(3000);
TestAsync = rez.Count.ToString(CultureInfo.InvariantCulture);
_lastId += rez.Count();
LastEngineId = _lastId.ToString(CultureInfo.InvariantCulture);
var lastOrDefault = rez.LastOrDefault();
if (lastOrDefault != null)
{
var nameEng = lastOrDefault.NameEngine;
const string act = "was added";
Welcome = string.Format("{0} {1}", nameEng, act);
}
else Welcome = "No new Engines";
}
Тут свойства LastEngineID, Welcome и void Test() связаны с соответствующими компонентами GUI WPF.Полезные ссылки:
1. MSDN
2. MSDN Magazine
Комментариев нет:
Отправить комментарий