还实现INotifyPropertyChanged的DependencyObject



对于Silverlight和WPF应用程序,我有一个自定义控件,其中包含一个ObservableCollection作为依赖属性。该控件的一个元素Border需要根据ObservableCollection中项目的组成来更改颜色。

例如,假设该集合包含动物、蔬菜和矿物质,称为ObjectList。如果至少有一种动物,我希望边界是红色的;如果没有动物,但至少有一种蔬菜,那就是绿色的;否则,该集合只有矿物,因此将显示为蓝色。

我创建了一个转换器,可以获取集合并确定颜色,所以有一个绑定,比如:

<Border Background="{Binding ObjectList, 
                     RelativeSource={RelativeSource Self}, 
                     Converter={StaticResource MyColorConverter}}" />

挑战在于,当项目从ObjectList中添加/删除时,我需要触发对背景颜色的重新评估;但ObjectList本身并没有改变。我想我有三个选择,但不确定哪一个可能是最佳实践:

  1. 每次添加或删除对象时创建一个新集合。这看起来很严厉,但会导致ObjectList被更改,从而触发后台更新。

  2. ObjectListCollectionChanged回调中,为后台属性调用UpdateTarget。由于UpdateTarget不适用于Silverlight,所以我只是删除并重新添加绑定——这又有点麻烦。

  3. 在我的自定义控件上实现INotifyPropertyChanged,并在CollectionChanged 的实现中在ObjectList上调用PropertyChanged

我最喜欢3,但我有一个DependencyObject,它也实现了INPC,这似乎很奇怪。是吗?有没有更优雅的方法?

MSDN文档推荐了一种方法(向下滚动到使用VisualStateManager的最佳实践;它是为完整的.Net编写的,但本节也非常适合Silverlight(。每当您的VisualStates依赖于自定义Control的属性/状态时,建议为每个影响VisualState的属性设置ChangedHandler,并从中调用专用UpdateVisualStates方法。评估您的条件,并在此方法中以编程方式设置VisualStates

即使您不使用VisualStates进行颜色更改,我也建议您遵循相同的模式。

为了简洁起见,以下代码不完整:

public ObservableCollection ObjectList {...}
public static readonly DependencyProperty ObjectListProperty =
    DependencyProperty.Register(...OnObjectListChanged...);
private static void OnObjectListChanged(...)
{ObjectList.CollectionChanged += OnObjectListCollectionChanged;}
private void OnObjectListCollectionChanged(...){ UpdateVisualStates(); }
private void UpdateVisualStates()
{
    //actually you have to instatiate a SolidColorBrush here
    if (ContainsAtLeastOneAnimal()) { m_border.Background = Colors.Red; }
    else if (ContainsAtLeastOneVegetable()) {m_border.Background = Colors.Green;}
    else { m_border.Background = Colors.Blue; }
}

如果您不想引用边界,请随意引入DependencyPropertyBorderColor并从xaml绑定到它。很好。而且有另一个活动部件真的没有问题。这比模拟整个ObjectList实例发生更改要好得多。

相关内容

  • 没有找到相关文章

最新更新