停止与 UI 混淆......这只是数据!
就个人而言,我认为最简单的方法是使用CompositeCollection
(或自定义枚举器)。这种思维方式的优点是它可以将其正确地分离为数据,这就是它的本质,而不是与自定义 UI 废话/绑定/相对源等混淆。
我会解释的。
考虑一下您正在尝试显示存储在myColors
集合中的“x”个动态生成的颜色,然后是表示“没有颜色”的内容(您的盒子里面有线条。)
首先,在您的应用程序中的某处定义一个“无颜色”标记,就像这样......
class NoColorToken{}
然后定义一个DataTemplate
定位那个类,像这样......
<DataTemplate DataType="{x:Type ns:NoColorToken}">
<TextBlock Text="Replace with template representing 'no color'" />
</DataTemplate>
您甚至可以使其更通用,将其称为 aNoSelectionToken
以与任何类型的列表一起使用。只需确保将 DataTemplate 范围限定为该特定位置的使用情况(即本示例中没有颜色。)
然后在您的代码中,只需将您的颜色填充到一个类CompositeCollection
的实例中NoColorToken
,如下所示:
var colorsAndToken = new CompositeCollection();
colorsAndToken.Add(new CollectionContainer(myColors));
colorsAndToken.Add(new NoColorToken());
itemsControl.ItemsSource = colorsAndToken;
对 MyColors 的更改(如果可观察到)将自动更新 UI。
如果它们不需要是可观察的(即没有单独的添加或删除),只需编写一个枚举器函数(本质上是CompositeCollection
内部操作的简化基础),事情就可以变得更加容易。
IEnumerable ColorsWithToken(IEnumerable colors){
foreach (var color in colors)
yield return color;
yield return new NoColorToken();
}
itemsControl.ItemsSource = ColorsWithToken(myColors);
同样,自定义枚举器方法不会跟踪对myColors
. 如果myColors
更改,您必须重新分配ItemsSource
. 但是,如果你走 的路线CompositeCollection
,它会自动处理更新,只是以新对象 为代价CompositeCollection
,但这就是它的用途。
顺便说一句,您还可以将上述内容包装在一个转换器中,该转换器为您处理任一方法,返回枚举数或CompositeCollection
用于纯 XAML 方法的 a,无论ItemsControl.ItemsSource
您将其应用于哪个方法。我实际上已经用AddNoSelectionPlaceholder
转换器做到了这一点。)
同样,我更喜欢它的原因是它将项目(包括“无颜色”项目)视为数据,这就是它的本质。更好的是,因为它是数据,它可以让你轻松地改变周围的事物。想要“无色”商品排在第一位吗?只需切换您添加它们的顺序。
colorsAndToken.Add(new NoColorToken());
colorsAndToken.Add(new CollectionContainer(myColors));
或者
yield return new NoColorToken();
foreach (var color in colors)
yield return color;
同样,现在只是数据。在数据模板或控件、绑定或其他任何地方都不需要做任何“聪明”的事情。更好的是,它现在也是完全可单元测试的。不需要用户界面。