Это забавная мелочь, которую я написал, когда имел дело со списками ошибок. Предположим, вы хотите, чтобы пользователь мог видеть, что есть ошибки, а не напрямую показывать им весь подробный список ошибок в его лице. Так есть, например, кнопка «Показать» ошибки, как в приложении, показанном справа.
Но уродливое «Показать ошибки» всегда видно, даже если нет ошибок для отображения. Я на самом деле только хочу , чтобы эта кнопка отображается , если есть ошибки, так что это указывает на то, что там есть ошибки, а затем пользователь может решить , хочет ли она видеть их или нет. Конечно, вы можете исправить это в своей модели представления — подписаться на события ObservableCollection ошибок и включать или отключать видимость при захвате этих событий, каждый раз, когда вам нужно это сделать. Идеально приемлемое решение. Но еще лучшее решение — это инкапсулировать это поведение — слово просто говорит это — в простой фрагмент кода, который можно использовать повторно.
Встречайте HideWhenCollectionEmptyBehavior. Он содержит коллекцию INotifyCollectionChanged, к которой вы можете привязать, а все остальное на самом деле настолько просто, что я собираюсь показать ее за один раз:
using System.Collections; using System.Collections.Specialized; using System.Windows; namespace Wp7nl.Behaviors { public class HideWhenCollectionEmptyBehavior : SafeBehavior<FrameworkElement> { protected override void OnSetup() { base.OnSetup(); SetVisibility(); } protected override void OnCleanup() { base.OnCleanup(); if (Collection != null) { Collection.CollectionChanged -= OnCollectionChanged; } } private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { SetVisibility(); } private void SetVisibility() { var collection = Collection as ICollection; AssociatedObject.Visibility = collection != null && collection.Count > 0 ? Visibility.Visible : Visibility.Collapsed; } } }
Поведение реализовано в виде SafeBehavior со вложенным свойством зависимостей «Collection» типа INotifyPropertyChanged, к которому вы можете привязать коллекцию, которую необходимо отслеживать. Ядром всего поведения является просто метод SetVisibility, который преобразует коллекцию в ICollection и проверяет, является ли она нулевой или пустой — в этом случае видимость объекта, к которому присоединено это поведение, установлена на Collapsed — если нет, то она установлена Видимый.
Прикрепленное свойство зависимости является довольно стандартным, за исключением последней части:
#region Collection public const string CollectionPropertyName = "Collection"; public INotifyCollectionChanged Collection { get { return (INotifyCollectionChanged)GetValue(CollectionProperty); } set { SetValue(CollectionProperty, value); } } public static readonly DependencyProperty CollectionProperty = DependencyProperty.Register( CollectionPropertyName, typeof(INotifyCollectionChanged), typeof(HideWhenCollectionEmptyBehavior), new PropertyMetadata(default(INotifyCollectionChanged), OnCollectionChanged)); public static void OnCollectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var behavior = d as HideWhenCollectionEmptyBehavior; var newValue = (INotifyCollectionChanged)e.NewValue; var oldValue = (INotifyCollectionChanged)e.OldValue; if (behavior != null) { if (oldValue != null) { oldValue.CollectionChanged -= behavior.OnCollectionChanged; } if (newValue != null) { newValue.CollectionChanged += behavior.OnCollectionChanged; } behavior.SetVisibility(); } } #endregion
Существует много слесарного дела, «просто чтобы быть в безопасности» — если связанная коллекция заменена, событие CollectionChanged отсоединяется от старой коллекции и присоединяется к новой коллекции. Все для предотвращения утечек памяти ? — но на самом деле я думаю, что когда-либо будет установлено только newValue. Но в любом случае, сделав свойство типа INotifyCollectionChanged, я уверен, что у меня будет самый низкий общий знаменатель, и у меня все еще будет CollectionChanged, который я могу ловушка.
Перетаскивая поведение поверх кнопки «Показать ошибки» и привязывая к наборам ошибок, мое приложение изначально выглядит так, как показано слева. Только когда я нажимаю «добавить ошибки», появляется кнопка «показать ошибки» (любезно предоставлено HideWhenCollectionEmptyBehavior), а затем, когда я нажимаю на нее, я вижу фактические ошибки.
Теперь, конечно, это довольно надуманный пример, но это реальный вариант использования. Как я уже писал, я на самом деле использую его для указания на наличие ошибок, но я могу вспомнить множество других сценариев, например, элемент пользовательского интерфейса, который отображается, когда у объекта есть дочерние объекты (например, у заказа есть строки заказа) без фактически отображая их — только указав, что они присутствуют.
Я написал это для работы в приложении Windows Phone, но код настолько общий, что он будет работать и на других платформах XAML, включая Windows 8.
Код поведения, вместе с моим прекрасным примером приложения * кашель * можно найти здесь
Для тех, кто хотел бы, чтобы я использовал «Any ()» вместо «Count> 0», я хотел бы отметить, что ICollection — это просто ICollection, а не ICollection <T> и, похоже, не поддерживает «Any ()». »