rubezh-TWnlenfritplesuk

Множественные привязки к свойству Visibility в WPF

Иногда требуется сделать возможность скрытия/отображения объектов на форме в WPF. Для этого можно создать в ViewModel свойство IsSomeObjectVisible и прибиндить к нему свойство Visibility через конвертер BooleanToVisibilityConverter. Но что делать, если нужно более сложное условие для отображения, например отображать прелоадер над объектом только тогда, когда происходит асинхронная загрузка и этот объект не скрыт? Попробуем разобраться...

Да, недавно понадобилось реализовать скрываемую часть формы, в которой имеются комбобоксы, загружаемые асинхронно и иногда они могут быть скрытыми. Соответственно, если панель скрыта, то и прелоадер нет необходимости отображать.

Есть три варианта, как реализовать логику отображения прелоадера:

1. Сделать комбобокс и спиннер потомками дополнительного layout manager-а, например Grid или StackPanel.

Этот вариант не плох, если нет больших требований к производительности и изыскам дизайна. Но нам он не подходит, т.к. форма несколько перегружена объектами и ширину колонок каждого layout-а придется синхронизировать с шириной родительского компонента. Да и не так интересен этот вариант с точки зрения программирования - слишком все просто! :)

2. Добавить в логику ViewModel, чтоб в пропертях, отвечающих за отображение сразу выдавались "правильные" значения, когда отображать прелоадер, а когда нет.

Но это противоречит правилам разделения труда между View и ViewModel. ViewModel в принципе не должна думать об отображении. Ее логика проста в этом смысле - есть процесс загрузки - IsInsurersLoading, а есть признак надобности этого поля - IsInsuredPatient, а дальше хоть земля гори!

3. Использовать MultiBinding и конвертер, принимающий массив входных значений и выдающий результат.

Так я и поступил, написал разметку (XAML):

<cl:SmallContinuousLoader>
<cl:SmallContinuousLoader.Resources>
<helpers:BooleanToVisibilityMultiConverter x:Key="BooleanToVisibilityMultiConverter" />
</cl:SmallContinuousLoader.Resources>
<cl:SmallContinuousLoader.Visibility>
<MultiBinding Converter="{StaticResource BooleanToVisibilityMultiConverter}">
<Binding Path="IsInsurersLoading"/>
<Binding Path="IsInsuredPatient"/>
</MultiBinding>
</cl:SmallContinuousLoader.Visibility>
</cl:SmallContinuousLoader>

Реализовал конвертер:

public class BooleanToVisibilityMultiConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return values.OfType<bool>().All(b => b) ? Visibility.Visible : Visibility.Collapsed;
}

public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

Конвертер получает на вход массив булевых значений и работает по методу логического AND, т.е. если во входных параметрах будет хоть один False, то результат будет False, точнее в нашем случае - Visibility.Collapsed.

1 1 1 1 1 1 1 1 1 1 Рейтинг 100%

Печать E-mail

Добавить комментарий


Защитный код
Обновить