Context-sensitive data binding in WPF
It's very convenient to assign ListBox.ItemsSource
a collection and then tweak ListBox.ItemTe开发者_开发问答mplate
to make the date look as I want.
Consider binding a simple list of sorted strings.
If the collection is large enough, eye-catching anchors would come handy.Here is a concept of what I want:
Wpf Example of a databinding http://bteffective.com/images/Data_Bindining_Example.pngBasically I want the first letter to be of different style, if it doesn't match the letter of the previous item. How can I address the previous item in my DataTemplate
?
You would likely need to parse your source list into a new list of objects that have three properties: The first letter of the word, the rest of the word, and a boolean that indicates if this entry is an "anchor". Then, your DataTemplate could be a TextBlock for the first letter followed by a TextBlock for the rest of the word. A style trigger on the IsAnchor boolean could then change the color of the first letter.
Another approach with MultiBinding
: I pass the collection as the parameter, look up the previous element and check if first letters match.
This approach is easier if the underlying collection is of ObservableCollection<T>
and changes. It is also slower, since displaying an element requires lookup of the previous element (O(n)), therefore, displaying n elements is O(n^2).
In Xaml:
<ListBox x:Name="lbExample" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Converter={StaticResource ResourceKey=first}}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource prevComparerConverter}">
<Binding />
<Binding RelativeSource="{RelativeSource AncestorType={x:Type ListBox}}" Path="ItemsSource"/>
</MultiBinding>
</DataTrigger.Binding>
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<TextBlock Text="{Binding Converter={StaticResource ResourceKey=rest}}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And in code:
public class PrevComparerConverter : IMultiValueConverter
{
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var item = (string)values[0];
var col = (ObservableCollection<string>)values[1];
var ind = col.IndexOf(item);
var res = true;
if (ind > 0 && item.Length > 0)
{
var prev = col[ind - 1];
if (prev.Length > 0 && char.ToLowerInvariant(prev[0]) == char.ToLowerInvariant(item[0]))
res = false;
}
return res;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
精彩评论