开发者

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.png

Basically 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();
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜