
Но уродливое «Показать ошибки» всегда видно, даже если нет ошибок для отображения. Я на самом деле только хочу , чтобы эта кнопка отображается , если есть ошибки, так что это указывает на то, что там есть ошибки, а затем пользователь может решить , хочет ли она видеть их или нет. Конечно, вы можете исправить это в своей модели представления — подписаться на события 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 ()». »


