wpf 更改列表框中最后一项的样式
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12125764/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Change style of last item in ListBox
提问by user1535848
I have listbox control which has list of colors. Here is code and Image:
我有包含颜色列表的列表框控件。这是代码和图像:
<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>
Image:
图片:


How would I change style of last item only like this:
我将如何仅像这样更改最后一项的样式:


回答by Rohit Vats
This can be achieved through converter which do the work of finding if its last item in the listbox -
这可以通过转换器来实现,该转换器执行查找列表框中的最后一项的工作 -
Converter
转换器
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();
}
}
And using that you can set the DataTemplate in your xaml class like this -
使用它,您可以像这样在 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>
回答by user1859022
to get this to work w/ a ListBox that changes over time I ended up using a MultiBinding:
为了让它与一个随时间变化的 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>
Note:the second binding is only used to get notified when the list changes
注意:第二个绑定仅用于在列表更改时获得通知
here is the corresponding MultivalueConverter
这里是对应的 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();
}
}
回答by Mark A. Donohoe
Stop Messing With The UI... It's Just Data!!!
别再搞 UI 了……这只是数据!!!
Personally, I think the easiest way to do this is using a CompositeCollection(or a custom enumerator). The advantage of this way of thinking is it properly separates this as data, which is what it is, rather than messing with custom UI nonsense/bindings/relative sources, etc.
就个人而言,我认为最简单的方法是使用CompositeCollection(或自定义枚举器)。这种思维方式的优点是它可以正确地将其作为数据分开,这就是它的本质,而不是与自定义 UI 废话/绑定/相关源等混为一谈。
I'll explain.
我来解释一下。
Consider you are trying to show 'x' number of dynamically-generated colors stored in a myColorscollection, followed by something that means 'no color' (your box with the line in it.)
考虑到您正在尝试显示存储在myColors集合中的'x' 个动态生成的颜色,然后是表示“无颜色”的内容(您的框内有线条)。
First, define a 'no color' token somewhere in your app, like so...
首先,在您的应用程序中的某处定义一个“无颜色”标记,就像这样......
class NoColorToken{}
Then define a DataTemplatetargeting that class, like so...
然后定义一个DataTemplate针对该类的目标,就像这样......
<DataTemplate DataType="{x:Type ns:NoColorToken}">
<TextBlock Text="Replace with template representing 'no color'" />
</DataTemplate>
You could even make it more generic calling it a
NoSelectionTokento use with any type of list. Just make sure to scope the DataTemplate to that specific location's usage (i.e. no color in this example.)
您甚至可以使它更通用,将其称为 a
NoSelectionToken以与任何类型的列表一起使用。只需确保将 DataTemplate 范围限定为该特定位置的使用(即在此示例中没有颜色。)
Then in your code, just stuff your colors into a CompositeCollectionfollowed by an instance of the NoColorTokenclass, like so:
然后在您的代码中,只需将您的颜色填充到类CompositeCollection的实例中NoColorToken,如下所示:
var colorsAndToken = new CompositeCollection();
colorsAndToken.Add(new CollectionContainer(myColors));
colorsAndToken.Add(new NoColorToken());
itemsControl.ItemsSource = colorsAndToken;
Changes to MyColors (if observable) will automatically update the UI.
对 MyColors 的更改(如果可观察到)将自动更新 UI。
Things can be made even easier if they don't need to be observable (i.e. No individual adds or removals) by simply writing an enumerator function (essentially the simplified basics of what CompositeCollectiondoes internally.)
如果不需要通过简单地编写枚举器函数(本质上是CompositeCollection内部操作的简化基础知识)来观察(即没有单独的添加或删除),事情可以变得更加容易。
IEnumerable ColorsWithToken(IEnumerable colors){
foreach (var color in colors)
yield return color;
yield return new NoColorToken();
}
itemsControl.ItemsSource = ColorsWithToken(myColors);
Again though, the custom enumerator approach won't track changes to myColors. If myColorschanges, you have to re-assign ItemsSource. However, if you go the route of the CompositeCollection, it handles updates automatically, just at the expense of a new object, the CompositeCollection, but that's what it's there for.
尽管如此,自定义枚举器方法不会跟踪对myColors. 如果myColors发生变化,您必须重新分配ItemsSource. 但是,如果您采用 的路线CompositeCollection,它会自动处理更新,只是以新对象 为代价CompositeCollection,但这就是它的用途。
By the way, you can also wrap the above in a converter that handles either approach for you, returning either the enumerator, or a CompositeCollectionfor a pure XAML approach regardless of which ItemsControl.ItemsSourceyou're applying it to. I've actually done exactly that with an AddNoSelectionPlaceholderconverter.)
顺便说一句,您还可以将上述内容包装在一个转换器中,该转换器为您处理任一方法,返回枚举器或CompositeCollection纯 XAML 方法的a ,无论ItemsControl.ItemsSource您将其应用于哪种方法。我实际上已经用AddNoSelectionPlaceholder转换器做到了。)
Again, the reason I prefer this is it treats the items, including the 'no color' item as data, which is what it is. Even better, since it is data, it lets you easily change things around. Want the 'no color' item to be first? Just switch the order you added them.
同样,我更喜欢这样做的原因是它将项目,包括“无颜色”项目视为数据,这就是它的本质。更好的是,因为它是数据,它可以让你轻松地改变周围的事物。想要“无色”商品排在第一位?只需切换您添加它们的顺序即可。
colorsAndToken.Add(new NoColorToken());
colorsAndToken.Add(new CollectionContainer(myColors));
or
或者
yield return new NoColorToken();
foreach (var color in colors)
yield return color;
Again, it's just data now. Nothing 'clever' needs to be done in the data template or control, bindings or anywhere else. Even better, it's now also fully unit-testable. No UI needed.
同样,现在只是数据。不需要在数据模板或控件、绑定或其他任何地方做任何“聪明”的事情。更好的是,它现在也完全可进行单元测试。不需要用户界面。

