我有列表框控件,其中包含颜色列表。这是代码和图片:
<ListBox Name="FillSelections" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Center" SelectedItem="{Binding SelectedColor}" SelectionMode="Single" Style="{StaticResource HorizontalListBoxStyle}" ItemsSource="{Binding FillColors}" ItemTemplate="{StaticResource ColorsItemTemplate}"></ListBox>
<DataTemplate x:Key="ColorsItemTemplate">
<Border BorderBrush="Transparent">
<Rectangle Width="20" StrokeThickness="1" Stroke="Black">
<Rectangle.Fill>
<SolidColorBrush Color="{Binding}" />
</Rectangle.Fill>
</Rectangle>
</Border>
图片:
我如何才能更改最后一项的样式:
答案 0 :(得分:19)
这可以通过转换器来实现,转换器可以查找列表框中的最后一项 -
<强>转换器强>
public class IsLastItemInContainerConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
DependencyObject item = (DependencyObject)value;
ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(item);
return ic.ItemContainerGenerator.IndexFromContainer(item)
== ic.Items.Count - 1;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
使用它可以在xaml类中设置DataTemplate,如下所示 -
<ListBox ItemContainerStyle="{StaticResource ColorsItemStyle}"/>
<Style x:Key="ColorsItemStyle">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self},
Converter={StaticResource IsLastItemInContainerConverter}}" Value="False">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate></DataTemplate> // Your template goes here
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self},
Converter={StaticResource IsLastItemInContainerConverter}}" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate></DataTemplate> // Your lastItem template goes here
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
答案 1 :(得分:7)
让这个工作与一个随时间变化的ListBox我最终使用MultiBinding:
<DataTemplate x:Key="myItemTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}"/>
<TextBlock x:Name="dots" Text="..."/>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Value="False">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource isLastItemInContainerConverter}">
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType=ListBoxItem}" />
<Binding Path="Items.Count" RelativeSource="{RelativeSource FindAncestor, AncestorType=ListBox}" />
</MultiBinding>
</DataTrigger.Binding>
<Setter TargetName="dots" Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
注意:第二个绑定仅用于在列表更改时收到通知
这是相应的MultivalueConverter
public class IsLastItemInContainerConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
DependencyObject item = (DependencyObject)values[0];
ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(item);
return ic.ItemContainerGenerator.IndexFromContainer(item) == ic.Items.Count - 1;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
答案 2 :(得分:0)
就我个人而言,我认为最简单的方法是使用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
为代价,但这就是它的用途。
顺便说一句,您也可以将以上内容包装在为您处理其中一种方法的转换器中,返回枚举数或用于纯XAML方法的CompositeCollection
,无论您使用哪种ItemsControl.ItemsSource
重新应用到。实际上,我实际上是使用AddNoSelectionPlaceholder
转换器完成的。)
同样,我更喜欢这样做的原因是它会将包括“无颜色”项目在内的项目视为数据,这就是事实。更好的是,由于它是数据,因此可以轻松地进行更改。希望将“无色”项目放在第一位吗?只需切换添加它们的顺序即可。
colorsAndToken.Add(new NoColorToken());
colorsAndToken.Add(new CollectionContainer(myColors));
或
yield return new NoColorToken();
foreach (var color in colors)
yield return color;
同样,现在只是数据。无需在数据模板或控件,绑定或其他任何地方完成“聪明”的工作。更好的是,它现在还可以完全进行单元测试。无需用户界面。