我怎么能知道,如果一个ListBoxItem的是WPF的列表框里面的最后一个项目? [英] How can i know if a ListBoxItem is the last item inside a Wpf's ListBox?

查看:1621
本文介绍了我怎么能知道,如果一个ListBoxItem的是WPF的列表框里面的最后一个项目?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我怎么能知道,如果一个 ListBoxItem的是集合的最后一个项目(在 ItemContainerStyle 或的模板)内的WPF的的ListBox

How can i know if a ListBoxItem is the last item of the collection (in the ItemContainerStyle or in the ItemContainer's template) inside a Wpf's ListBox?

ItemContainer >这个问题是因为我需要知道,如果一个项目是为了显示它的另一种方式的最后一个项目。例如:假设我想显示分号,但最后一个分隔的项目:; B; C

That question is because I need to know if an item is the last item to show it in other way. For example: suppose i want to show items separated by semi-colons but the last one: a;b;c

这是很容易做HTML和CCS,CCS的使用选择。 ?但是,我怎么能做到这一点在WPF

This is easy to do in html and ccs, using ccs selector. But, how can i do this in Wpf?

推荐答案

,因为它似乎是的而难以实施索引附加属性来ListBoxItem的做这项工作的权利,我相信更简单的方法来完成,这将是在MVVM。
。您可以在必要的逻辑(一个IsLast属性,等等)添加到列表的实体类型,让视图模型处理这,更新它当集合被修改或替换。

As it seems to be rather difficult to implement an "Index" attached property to ListBoxItem to do the job right, I believe the easier way to accomplish that would be in MVVM. You can add the logic necessary (a "IsLast" property, etc) to the entity type of the list and let the ViewModel deal with this, updating it when the collection is modified or replaced.

修改

一些尝试后,我成功地实现ListBoxItems的索引(因此检查最后一个)使用附加属性的组合和继承列表框。检查出来:

After some attempts, I managed to implement indexing of ListBoxItems (and consequently checking for last) using a mix of attached properties and inheriting ListBox. Check it out:

public class IndexedListBox : System.Windows.Controls.ListBox
{
    public static int GetIndex(DependencyObject obj)
    {
        return (int)obj.GetValue(IndexProperty);
    }
    public static void SetIndex(DependencyObject obj, int value)
    {
        obj.SetValue(IndexProperty, value);
    }
    /// <summary>
    /// Keeps track of the index of a ListBoxItem
    /// </summary>
    public static readonly DependencyProperty IndexProperty =
        DependencyProperty.RegisterAttached("Index", typeof(int), typeof(IndexedListBox), new UIPropertyMetadata(0));


    public static bool GetIsLast(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsLastProperty);
    }
    public static void SetIsLast(DependencyObject obj, bool value)
    {
        obj.SetValue(IsLastProperty, value);
    }
    /// <summary>
    /// Informs if a ListBoxItem is the last in the collection.
    /// </summary>
    public static readonly DependencyProperty IsLastProperty =
        DependencyProperty.RegisterAttached("IsLast", typeof(bool), typeof(IndexedListBox), new UIPropertyMetadata(false));


    protected override void OnItemsSourceChanged(System.Collections.IEnumerable oldValue, System.Collections.IEnumerable newValue)
    {
        // We capture the ItemsSourceChanged to check if the new one is modifiable, so we can react to its changes.

        var oldSource = oldValue as INotifyCollectionChanged;
        if(oldSource != null)
            oldSource.CollectionChanged -= ItemsSource_CollectionChanged;

        var newSource = newValue as INotifyCollectionChanged;
        if (newSource != null)
            newSource.CollectionChanged += ItemsSource_CollectionChanged;

        base.OnItemsSourceChanged(oldValue, newValue);
    }

    void ItemsSource_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        this.ReindexItems();
    }

    protected override void PrepareContainerForItemOverride(System.Windows.DependencyObject element, object item)
    {
        // We set the index and other related properties when generating a ItemContainer
        var index = this.Items.IndexOf(item); 
        SetIsLast(element, index == this.Items.Count - 1);
        SetIndex(element, index);

        base.PrepareContainerForItemOverride(element, item);
    }

    private void ReindexItems()
    {
        // If the collection is modified, it may be necessary to reindex all ListBoxItems.
        foreach (var item in this.Items)
        {
            var itemContainer = this.ItemContainerGenerator.ContainerFromItem(item);
            if (itemContainer == null) continue;

            int index = this.Items.IndexOf(item);
            SetIsLast(itemContainer, index == this.Items.Count - 1);
            SetIndex(itemContainer, index);
        }
    }
}

要测试它,我们设置一个简单的视图模型和项目类:

To test it, we setup a simple ViewModel and an Item class:

public class ViewModel : INotifyPropertyChanged
{
    #region INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    #endregion

    private ObservableCollection<Item> items;
    public ObservableCollection<Item> Items
    {
        get { return this.items; }
        set
        {
            if (this.items != value)
            {
                this.items = value;
                this.OnPropertyChanged("Items");
            }
        }
    }

    public ViewModel()
    {
        this.InitItems(20);
    }

    public void InitItems(int count)
    {

        this.Items = new ObservableCollection<Item>();
        for (int i = 0; i < count; i++)
            this.Items.Add(new Item() { MyProperty = "Element" + i });
    }

}

public class Item
{
    public string MyProperty { get; set; }

    public override string ToString()
    {
        return this.MyProperty;
    }
}



视图:

The view:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication3"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="WpfApplication3.MainWindow"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <DataTemplate x:Key="DataTemplate">
        <Border x:Name="border">
            <StackPanel Orientation="Horizontal">
                <TextBlock TextWrapping="Wrap" Text="{Binding (local:IndexedListBox.Index), RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}" Margin="0,0,8,0"/>
                <TextBlock TextWrapping="Wrap" Text="{Binding (local:IndexedListBox.IsLast), RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}" Margin="0,0,8,0"/>
                <ContentPresenter Content="{Binding}"/>
            </StackPanel>
        </Border>
        <DataTemplate.Triggers>
            <DataTrigger Binding="{Binding (local:IndexedListBox.IsLast), RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}" Value="True">
                <Setter Property="Background" TargetName="border" Value="Red"/>
            </DataTrigger>
        </DataTemplate.Triggers>
    </DataTemplate>
</Window.Resources>
<Window.DataContext>
    <local:ViewModel/>
</Window.DataContext>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="0.949*"/>
    </Grid.RowDefinitions>

    <local:IndexedListBox ItemsSource="{Binding Items}" Grid.Row="1" ItemTemplate="{DynamicResource DataTemplate}"/>

    <Button Content="Button" HorizontalAlignment="Left" Width="75" d:LayoutOverrides="Height" Margin="8" Click="Button_Click"/>
    <Button Content="Button" HorizontalAlignment="Left" Width="75" Margin="110,8,0,8" Click="Button_Click_1"  d:LayoutOverrides="Height"/>
    <Button Content="Button" Margin="242,8,192,8" Click="Button_Click_2"  d:LayoutOverrides="Height"/>
</Grid>
</Window>

在该视图的我后面的代码把一些逻辑来测试更新集合时,溶液的行为:

In the view's code behind I put some logic to test the behavior of the solution when updating the collection:

public partial class MainWindow : Window
{
    public ViewModel ViewModel { get { return this.DataContext as ViewModel; } }

    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        this.ViewModel.Items.Insert( 5, new Item() { MyProperty= "NewElement" });
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        this.ViewModel.Items.RemoveAt(5);
    }

    private void Button_Click_2(object sender, RoutedEventArgs e)
    {
        this.ViewModel.InitItems(new Random().Next(10,30));
    }
}

这解决方案可以处理静态的列表,也ObservableCollections和添加,删除,插入的项目吧。希望你觉得它有用。

This solution can handle static lists and also ObservableCollections and adding, removing, inserting items to it. Hope you find it useful.

修改

与CollectionViews并测试它工作得很好。

Tested it with CollectionViews and it works just fine.

在第一测试中,我在ListBox.Items改变排序/ GroupDesc​​riptions。当其中一人被改变,ListBox中重新创建containeirs,然后PrepareContainerForItemOverride命中。因为它看起来在ListBox.Items本身的右手食指,顺序是正确更新。

In the first test, I changed Sort/GroupDescriptions in the ListBox.Items. When one of them was changed, the ListBox recreates the containeirs, and then PrepareContainerForItemOverride hits. As it looks for the right index in the ListBox.Items itself, the order is updated correctly.

在第二次我在一个视图模型做出的ListCollectionView Items属性。在这种情况下,当描述被改变,CollectionChanged升高和列表框预期反应。

In the second I made the Items property in the ViewModel a ListCollectionView. In this case, when the descriptions were changed, the CollectionChanged was raised and the ListBox reacted as expected.

这篇关于我怎么能知道,如果一个ListBoxItem的是WPF的列表框里面的最后一个项目?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆