我如何知道 ListBoxItem 是否是 Wpf 的 ListBox 中的最后一个项目?

2023-12-07

我怎么知道是否ListBoxItem是集合的最后一项(在ItemContainerStyle或在ItemContainer的模板)在 Wpf 内ListBox?

这个问题是因为我需要知道某个项目是否是最后一个以其他方式显示的项目。例如:假设我想显示用分号分隔的项目,但最后一个:a;b;c

使用 css 选择器在 html 和 ccs 中很容易做到这一点。但是,我怎样才能在 Wpf 中做到这一点?


看起来似乎是这样实施起来相当困难ListBoxItem 的“Index”附加属性可以正确完成工作,我相信更简单的方法是在 MVVM 中实现这一点。 您可以将必要的逻辑(“IsLast”属性等)添加到列表的实体类型中,并让 ViewModel 处理此问题,并在修改或替换集合时更新它。

EDIT

经过一番尝试,我成功地使用附加属性和继承 ListBox 的组合来实现 ListBoxItems 的索引(并因此检查最后一个)。一探究竟:

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);
        }
    }
}

为了测试它,我们设置了一个简单的 ViewModel 和一个 Item 类:

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;
    }
}

风景:

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

在视图的代码后面,我添加了一些逻辑来测试更新集合时解决方案的行为:

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 以及向其中添加、删除、插入项目。希望你觉得它有用。

EDIT

使用 CollectionViews 对其进行了测试,效果很好。

在第一个测试中,我更改了 ListBox.Items 中的 Sort/GroupDescriptions。当其中之一发生更改时,ListBox 会重新创建容器,然后单击“PrepareContainerForItemOverride”。当它在 ListBox.Items 本身中查找正确的索引时,顺序会正确更新。

在第二个中,我将 ViewModel 中的 Items 属性设置为 ListCollectionView。在本例中,当描述发生更改时,将引发 CollectionChanged 并且 ListBox 按预期做出反应。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我如何知道 ListBoxItem 是否是 Wpf 的 ListBox 中的最后一个项目? 的相关文章

  • 无法使用已与其底层 RCW 分离的 COM 对象。在 oledb 中

    我收到此错误 但我不知道我做错了什么 下面的代码在backrgroundworker中 将异常详细信息复制到剪贴板 System Runtime InteropServices InvalidComObjectException 未处理 通
  • 如何使用GDB修改内存内容?

    我知道我们可以使用几个命令来访问和读取内存 例如 print p x 但是如何更改任何特定位置的内存内容 在 GDB 中调试时 最简单的是设置程序变量 参见GDB 分配 http sourceware org gdb current onl
  • 将数组向左或向右旋转一定数量的位置,复杂度为 o(n)

    我想编写一个程序 根据用户的输入 正 gt 负 include
  • 未解决的包含:“cocos2d.h” - Cocos2dx

    当我在 Eclipse 中导入 cocos2dx android 项目时 我的头文件上收到此警告 Unresolved inclusion cocos2d h 为什么是这样 它实际上困扰着我 该项目可以正确编译并运行 但我希望这种情况消失
  • 使闭包捕获的变量变得易失性

    闭包捕获的变量如何与不同线程交互 在下面的示例代码中 我想将totalEvents 声明为易失性的 但C 不允许这样做 是的 我知道这是错误的代码 这只是一个例子 private void WaitFor10Events volatile
  • 实时服务器上的 woff 字体 MIME 类型错误

    我有一个 asp net MVC 4 网站 我在其中使用 woff 字体 在 VS IIS 上运行时一切正常 然而 当我将 pate 上传到 1and1 托管 实时服务器 时 我得到以下信息 网络错误 404 未找到 http www co
  • WPF 中的调度程序和异步等待

    我正在尝试学习 WPF C 中的异步编程 但我陷入了异步编程和使用调度程序的困境 它们是不同的还是在相同的场景中使用 我愿意简短地回答这个问题 以免含糊不清 因为我知道我混淆了 WPF 中的概念和函数 但还不足以在功能上正确使用它 我在这里
  • C#:如何防止主窗体过早显示

    在我的 main 方法中 我像往常一样启动主窗体 Application EnableVisualStyles Application SetCompatibleTextRenderingDefault false Application
  • 如何返回 json 结果并将 unicode 字符转义为 \u1234

    我正在实现一个返回 json 结果的方法 例如 public JsonResult MethodName Guid key var result ApiHelper GetData key Data is stored in db as v
  • vector 超出范围后不清除内存

    我遇到了以下问题 我不确定我是否错了或者它是一个非常奇怪的错误 我填充了一个巨大的字符串数组 并希望在某个点将其清除 这是一个最小的例子 include
  • 从路径中获取文件夹名称

    我有一些路c server folderName1 another name something another folder 我如何从那里提取最后一个文件夹名称 我尝试了几件事 但没有成功 我只是不想寻找最后的 然后就去休息了 Thank
  • Github Action 在运行可执行文件时卡住

    我正在尝试设置运行google tests on a C repository using Github Actions正在运行的Windows Latest 构建过程完成 但是当运行测试时 它被卡住并且不执行从生成的可执行文件Visual
  • 从库中捕获主线程 SynchronizationContext 或 Dispatcher

    我有一个 C 库 希望能够将工作发送 发布到 主 ui 线程 如果存在 该库可供以下人员使用 一个winforms应用程序 本机应用程序 带 UI 控制台应用程序 没有 UI 在库中 我想在初始化期间捕获一些东西 Synchronizati
  • 当操作繁忙时,表单不执行任何操作(冻结)

    我有一个使用 C 的 WinForms 应用程序 我尝试从文件中读取一些数据并将其插入数据表中 当此操作很忙时 我的表单冻结并且无法移动它 有谁知道我该如何解决这个问题 这可能是因为您在 UI 线程上执行了操作 将文件和数据库操作移至另一个
  • 控制到达非 void 函数末尾 -wreturn-type

    这是查找四个数字中的最大值的代码 include
  • 将文本叠加在图像背景上并转换为 PDF

    使用 NET 我想以编程方式创建一个 PDF 它仅包含一个背景图像 其上有两个具有不同字体和位置的标签 我已阅读过有关现有 PDF 库的信息 但不知道 如果适用 哪一个对于如此简单的任务来说最简单 有人愿意指导我吗 P D 我不想使用生成的
  • WCF:将随机数添加到 UsernameToken

    我正在尝试连接到用 Java 编写的 Web 服务 但有些东西我无法弄清楚 使用 WCF 和 customBinding 几乎一切似乎都很好 除了 SOAP 消息的一部分 因为它缺少 Nonce 和 Created 部分节点 显然我错过了一
  • C 中的异或运算符

    在进行按位操作时 我在确定何时使用 XOR 运算符时遇到一些困难 按位与和或非常简单 当您想要屏蔽位时 请使用按位 AND 常见用例是 IP 寻址和子网掩码 当您想要打开位时 请使用包含或 然而 XOR 总是让我明白 我觉得如果在面试中被问
  • 如何在 C++ BOOST 中像图形一样加载 TIFF 图像

    我想要加载一个 tiff 图像 带有带有浮点值的像素的 GEOTIFF 例如 boost C 中的图形 我是 C 的新手 我的目标是使用从源 A 到目标 B 的双向 Dijkstra 来获得更高的性能 Boost GIL load tiif
  • 使用按位运算符相乘

    我想知道如何使用按位运算符将一系列二进制位相乘 但是 我有兴趣这样做来查找二进制值的十进制小数值 这是我正在尝试做的一个例子 假设 1010010 我想使用每个单独的位 以便将其计算为 1 2 1 0 2 2 1 2 3 0 2 4 虽然我

随机推荐

  • 在 Spring Boot 中每个数据库连接开始时运行 SQL 语句

    如何使用Spring Boot获得数据库连接后直接运行自定义SQL语句 每次建立新连接时都需要运行 SQL 该解决方案应该与 Spring Boot 默认 DataSource 实现 我认为是 Tomcat 池数据源 一起使用 声明是什么并
  • 什么是互递归类型?

    如果在 ML 中 递归数据类型的示例是 datatype llist Nil Node of int llist 什么是机器学习中的相互递归数据类型以及它的示例是什么 这些愚蠢的数据类型就是这样的一个例子 datatype a A Ab o
  • FirebaseInstanceId:传递消息时出错:MI 设备中未找到 ServiceIntent

    当应用程序长时间处于后台时 我们发现了此错误 我在小米设备中发现了这个问题 我在三星进行了测试 它运行完美 但在小米中 它总是抛出相同的错误 None
  • findOne 可以先匹配还是最后匹配?

    我专门使用猫鼬 尽管我不认为这有那么重要 例如 假设我有一个名为 MongoQueue 的集合 并且我向该队列添加了一些人 MongoQueue save function err firstPerson if err console lo
  • 使用不同的因变量重复回归

    我已经在 Stack 和 google 上搜索了解决方案 但没有找到解决我的问题的方法 我有大约 40 个因变量 我的目标是获得调整后的均值 lsmeans 在考虑了一些协变量后 我需要调整 A 组和 B 组的均值 我的最终对象应该是一个数
  • 在 matplotlib 中使用更多颜色进行绘图

    我正在尝试使用 matplotlib 绘制散点图 但收到 IndexError 从空列表中弹出 错误 我不知道如何修复它 import matplotlib pyplot as plt import matplotlib import nu
  • 表格单元格在行内右对齐

    我试图弄清楚如何将单元格移动到 HTML 表格的左侧 我想在最后一行使用更少的单元格 默认情况下它位于右侧 例如我有这张表 table tr th one th th two th th three th tr tr td one td t
  • Android v2 MapFragment 在 Scrollview 中滚动时抖动

    我正在使用 SupportMapFragment 在 ScrollView 中显示静态地图 我不喜欢移动 缩放地图 只显示位置 当我向下 向上滚动时 地图在其边界内晃动 感觉非常滞后 我的问题是 如何消除这种滞后 或者如何使用 v2 api
  • 在 Java 中 Ping 多个服务器 [重复]

    这个问题在这里已经有答案了 我有一个程序可以向服务器发送 ping 请求 该列表很大 如果IP无法到达 需要时间才能转到下一个IP 我希望 对于每一个IP 它应该创建一个新线程并同时处理所有线程 这是代码 for int i 0 i lt
  • Jackson @JsonProperty(required=true) 不会抛出异常

    我正在使用 jackson 2 2 注释 JsonProperty 并将 required 设置为 true 通过 ObjectMapper readValue 方法反序列化不包含该属性的 json 文件时 不会引发异常 它应该以不同的方式
  • 在 SQL Server 中执行列值[重复]

    这个问题在这里已经有答案了 我需要对 SQL 表中保存的值进行算术运算 例如 我在下一列中的值为 5 10 我想要 15 EQUATION VALUE 2 5 7 6 8 14 根据方程式我需要计算该值 正如您现在所知 SQL Server
  • 在运行时修改类定义的注释字符串参数

    想象一下有一个类 Something someProperty some value public class Foobar 它已经编译 我无法控制源代码 并且是 jvm 启动时类路径的一部分 我希望能够在运行时将 某些值 更改为其他值 这
  • 过程中表值参数中的标识列,如何定义 DataTable

    是否可以将类型为 table 的参数以及类型为 int IDENTITY 1 1 的列传递给过程 并使用作为输入参数传递的 DataTable 对象来执行此存储过程 我收到以下错误 插入表变量不允许的标识列 表值参数 xxxxx 的数据不符
  • 我们如何解释表达式 (++x)+(++x)+(++x) 的结果? [复制]

    这个问题在这里已经有答案了 x 1 std cout lt lt x x x 我期望输出是11 但实际上是12 Why 我们通过期待来解释它未定义的行为而不是任何特定的结果 由于表达式尝试多次修改 x 而无需干预序列点 its 行为未定义
  • 生成16位灰度BitmapData并保存到文件

    我试图在 C 中从随机数据生成 16 位灰度位图 但它在 Marshal Copy 上崩溃了 这是我的代码 Bitmap b16bpp private void GenerateDummy16bitImage b16bpp new Bitm
  • 从响应中提取图像数据:Angular 2

    响应具有图像数据 但我无法从响应中提取它 客户代码 download this http get http localhost 9000 download this fileid subscribe data gt this image d
  • Wpf 图像控制阻止文件

    我有一个简单的Window带按钮和第二个Window当我点击时打开Button 第二Window has a Image控件 显示 png 文件 所以如果我使用FileObject财产为Binding一切正常 我可以从中删除文件File E
  • Safari 开发工具 JS 控制台窗口中的 $1 和 $2 等是什么?

    当我在 Safari 上运行开发工具并在控制台窗口中使用 querySelector 时 我得到正确的值 然后是 1 和 2 等等 任何人都可以帮助理解它们的含义吗 Chrome 0 4 开发工具会记住您在选项卡 或 配置文件 面板 中选择
  • Ruby 中的 Google Apps API 和服务帐户出现问题

    我在获取用于实例化驱动器服务帐户的示例代码时遇到一些问题 我已按照指示在 API 控制台中设置了服务帐户 并包含了 https www googleapis com auth drive 但运行此命令会生成以下错误 授权失败 服务器消息 S
  • 我如何知道 ListBoxItem 是否是 Wpf 的 ListBox 中的最后一个项目?

    我怎么知道是否ListBoxItem是集合的最后一项 在ItemContainerStyle或在ItemContainer的模板 在 Wpf 内ListBox 这个问题是因为我需要知道某个项目是否是最后一个以其他方式显示的项目 例如 假设我