В первой части я рассказал, как использовать 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
Комментариев нет:
Отправить комментарий