Использование такого компонента как BusyIndicator привнесит в наше приложение приятные (индикация процесса) и полезные (блокировка элемента управления) качества. Однако до последнего времени я редко использовал его, т.к. при асинхронном получении источника данных приходилось постоянно писать дополнительный код для включения/выключения. При синхронной работе ситуация вроде как упрощается, но использование MVVM-модели всё-равно требует дополнительных телодвижений. Особенно, если
Поэтому, я решил максимально автоматизировать этот процесс, чтобы мне не приходилось писать ни строчки кода. Итак:
Постановка задачи:
Свойство биндинга
Первое, что мне пришло в голову (и это даже визуально заработало) — это написать нечто наподобие такого:
А ну, кто сможет сразу раскритиковать этот код?
Вот и мне он тоже сразу не понравился. Отладка подтвердила мои опасения: получение списка происходило дважды — для
«Не беда!» — сказал я и чуть изменил метод получения списка:
Теперь получение данных происходило один раз и всё работало так как и задумывалось, но, этот метод мне всё-равно не нравился.
Во-первых, нужно регистрировать конвертер, во-вторых, писать довольно много одинаковых букафф, не забывая синхронизировать биндинги списка и индикатора, если вдруг что-то изменится, в-третьих, я не уверен, что получение
Следующей идеей было использование
До сих пор мне не выдавалась возможность глубоко в этом разобраться на реальном интересном примере, так что в следующей статье Создание Attached Property для BusyIndicator шаг за шагом я расскажу, что у меня получилось.
Спасибо тем кто дочитал до конца.
BusyIndicator добавляется в самом конце разработки формы.Поэтому, я решил максимально автоматизировать этот процесс, чтобы мне не приходилось писать ни строчки кода. Итак:
Постановка задачи:
- Обеспечить автоматическую индикацию для любых списков, использующих в качестве источника данных значение свойства
ItemsSource. - Признаком, что данные получены будем считать не пустое значение свойства
ItemsSource. - В качестве
BusyIndicator'а можно использовать любой элемент управления только бы он имелboolean-свойствоIsBusy. - Всё дополнительное кодирование должно быть реализовано в представлении (View) формы и XAML-код должен иметь такой шаблон:
<BusyIndicator ...> <ListBox ItemsSource="{Binding DataList, IsAsync=true}" ...> ... </ListBox> <BusyIndicator>
Свойство биндинга
IsAsync=true в примере можно опустить, в этом случае рассуждения особо не изменяться, но в данной статье я буду приводить примеры именно асихронного получения данных, т.к. если требуется индикация процесса, то получение данных занимает ощутимое время, а раз так, то мы же не хотим, чтобы наше приложение зависало при этом, а раз так — то асинхронный биндинг наше всё. Тем более, что реализовать его нам ничего не стоит: IsAsync=true в XAML-е и в коде ViewModel'и:private IEnumerable _dataList = null; public IEnumerable DataList { get { if (_dataList == null) _dataList = Model.GetDataList(...); return _dataList; } private set { if (_dataList == value) return; _dataList = value; NotifyPropertyChanged("DataList"); } } public void RefreshDataList() { DataList = null; }
Первое, что мне пришло в голову (и это даже визуально заработало) — это написать нечто наподобие такого:
<BusyIndicator IsBusy="{Binding DataList, IsAsync=true, Converter={StaticResource NullToBool}"> <ListBox ItemsSource="{Binding DataList, IsAsync=true}" ...> ... </ListBox> <BusyIndicator>
А ну, кто сможет сразу раскритиковать этот код?
Вот и мне он тоже сразу не понравился. Отладка подтвердила мои опасения: получение списка происходило дважды — для
BusyIndicatorа и для списка.«Не беда!» — сказал я и чуть изменил метод получения списка:
private object _dataListSync = new nbject(); private IEnumerable _dataList = null; public IEnumerable DataList { get { lock (_dataListSync) { if (_dataList == null) _dataList = Model.GetDataList(...); return _dataList; } } }
Теперь получение данных происходило один раз и всё работало так как и задумывалось, но, этот метод мне всё-равно не нравился.
Во-первых, нужно регистрировать конвертер, во-вторых, писать довольно много одинаковых букафф, не забывая синхронизировать биндинги списка и индикатора, если вдруг что-то изменится, в-третьих, я не уверен, что получение
DataList для индикатора всегда вызовется до получения DataList для списка.Следующей идеей было использование
attached property. До сих пор мне не выдавалась возможность глубоко в этом разобраться на реальном интересном примере, так что в следующей статье Создание Attached Property для BusyIndicator шаг за шагом я расскажу, что у меня получилось.
Спасибо тем кто дочитал до конца.
