别再搞乱UI了...它只是数据!!!
个人认为,最简单的方法是使用CompositeCollection
(或自定义枚举器)。这种思考方式的优点在于,它将其正确地作为数据分离出来,而不是搞乱自定义UI绑定/相对源等。
我来解释一下。
假设您要显示存储在myColors
集合中的“x”个动态生成的颜色,然后是某些表示“无颜色”的东西(带有线条的框)。
首先,在应用程序中定义一个“无颜色”标记,如下所示...
class NoColorToken{}
然后定义一个目标该类的
DataTemplate
,如下所示...
<DataTemplate DataType="{x:Type ns:NoColorToken}">
<TextBlock Text="Replace with template representing 'no color'" />
</DataTemplate>
您甚至可以将其更通用,称之为NoSelectionToken
,可用于任何类型的列表。只需确保将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
,从而实现了对应用于它的任何ItemsControl.ItemsSource
的纯XAML方法。 实际上,我就是用一个AddNoSelectionPlaceholder
转换器做到了这一点。
再次强调,我喜欢这种方法的原因是它将项目(包括“无颜色”项)视为数据(它本来就是),这使得您可以轻松地对它们进行更改。想让“无颜色”的项首先显示? 只需切换添加它们的顺序即可。
colorsAndToken.Add(new NoColorToken())
colorsAndToken.Add(new CollectionContainer(myColors))
或者
yield return new NoColorToken();
foreach (var color in colors)
yield return color;
现在,它只是数据。在数据模板、控件、绑定或任何其他地方都不需要进行任何“聪明”的操作。更好的是,现在这些操作也可以进行完全单元测试,无需使用UI。