当前位置: 首页 > ai >正文

WPF——自定义ListBox

在阅读本文前,最好先看看WPF——自定义RadioButton

背景

WPF中实现单选功能通常有两种方案:
- RadioButton组:传统方案,但代码冗余
- ListBox定制:通过样式改造,兼顾数据绑定和UI灵活性

需求

一组选项中,选中某个选项(选项需要横向排列,同时选中效果与未选中效果要能明确显示),就将这个选项的值写入到后端。

设计选型

RadioButton方案

通过RadioButton来实现,是肯定可行的,

但是对于一组RadioButton,需要设置组名;

同时每个RadioButton在Checked时都要触发事件,也需要为它们设置相应的事件,不利于后台绑定:也就是说要将选中值写入VM比较麻烦,因为所有的都需要实现;

并且还存在一个问题,所有RadioButton需要手动去设置相应的显示内容,不能使用一个集合以便于管理。

ListBox方案

通过ListBox也是可行的,只是它就需要进行一些改造了,因为ListBox默认的是纵向排列,同时它没有一个明确的选中与未选中效果;

但是它可以绑定集合,同时通过自定义,可以比较轻松的将选中值写入到VM中;或者通过item的选中事件即可将选中值写入到VM中。

方案对比

方案代码量数据绑定布局灵活性维护成本
RadioButton组困难
ListBox定制简单
 

后续基于ListBox进行实现。

实现

样式定义

 <Style x:Key="RadioListBoxStyle" TargetType="{x:Type ListBox}"><!--  基础样式继承原有ListBoxStyle1  --><Setter Property="Background" Value="{StaticResource ListBox.Static.Background}" /><Setter Property="BorderBrush" Value="{StaticResource ListBox.Static.Border}" /><Setter Property="BorderThickness" Value="1" /><Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" /><Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" /><Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" /><Setter Property="ScrollViewer.CanContentScroll" Value="true" /><Setter Property="ScrollViewer.PanningMode" Value="Both" /><Setter Property="Stylus.IsFlicksEnabled" Value="False" /><Setter Property="VerticalContentAlignment" Value="Center" /><!--  关键修改1:禁用默认选中效果  --><Setter Property="ItemContainerStyle"><Setter.Value><Style TargetType="{x:Type ListBoxItem}"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type ListBoxItem}"><Border Background="Transparent"><ContentPresenter /></Border></ControlTemplate></Setter.Value></Setter></Style></Setter.Value></Setter><!--  ItemsPanel为水平布局  --><Setter Property="ItemsPanel"><Setter.Value><ItemsPanelTemplate>  <!--  改为水平排列  --><StackPanel Orientation="Horizontal" /></ItemsPanelTemplate></Setter.Value></Setter><!--  自定义ItemTemplate模拟RadioButton  --><Setter Property="ItemTemplate"><Setter.Value><DataTemplate><DockPanel LastChildFill="True"><!--  RadioButton部分  --><RadioButtonMargin="5,0,10,0"VerticalAlignment="Center"DockPanel.Dock="Left"Focusable="False"IsChecked="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}" /><!--  文本部分  --><TextBlockMargin="0,0,5,0"VerticalAlignment="Center"Text="{Binding}" /></DockPanel></DataTemplate></Setter.Value></Setter><!--  模板  --><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type ListBox}"><Borderx:Name="Bd"Padding="1"Background="{TemplateBinding Background}"BorderBrush="{TemplateBinding BorderBrush}"BorderThickness="{TemplateBinding BorderThickness}"SnapsToDevicePixels="true"><ScrollViewer Padding="{TemplateBinding Padding}" Focusable="false"><ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" /></ScrollViewer></Border><ControlTemplate.Triggers><Trigger Property="IsEnabled" Value="false"><Setter TargetName="Bd" Property="Background" Value="{StaticResource ListBox.Disabled.Background}" /><Setter TargetName="Bd" Property="BorderBrush" Value="{StaticResource ListBox.Disabled.Border}" /></Trigger><MultiTrigger><MultiTrigger.Conditions><Condition Property="IsGrouping" Value="true" /><Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="false" /></MultiTrigger.Conditions><Setter Property="ScrollViewer.CanContentScroll" Value="false" /></MultiTrigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style>

数据绑定

    <Window.DataContext><local:Tests /></Window.DataContext>

Tests如下,以下可以根据需要自行实现通知属性。

public class Tests:INotifyPropertyChanged
{readonly List<string> testDatas = ["test0","test1","test2","test3","test4",];private string _selectedValue;public string SelectedValue{get => _selectedValue;set { _selectedValue = value; OnPropertyChanged(); }}public List<string> TestDatas { get; set; }public Tests(){TestDatas = testDatas;}//INotifyPropertyChanged实现
}

ListBox如下:

<ListBoxMargin="0,183,462,192"ItemsSource="{Binding TestDatas}"SelectedItem="{Binding SelectedValue, Mode=TwoWay}"Style="{DynamicResource RadioListBoxStyle}" />

效果展示

图:横向排列的单选ListBox,左侧为RadioButton,右侧为文本

http://www.xdnf.cn/news/15891.html

相关文章:

  • 注解 + AOP 的方式记录日志到 t_ops_sync_log 表
  • 使用相机不同曝光时间测试灯光闪烁频率及Ai解释
  • 宝塔访问lnmp项目,跳转不到项目根目录问题解决
  • 后训练(Post-training)语言模型
  • Linux system-timesyncd时间同步机制详解
  • Django模板系统
  • Oracle 数据库共享池与大池调优指南
  • RuoYi配置多数据源失效
  • 【烧脑算法】拓扑排序:从“依赖”到“序列”,理解题目中的先后逻辑
  • 虚拟电厂蓄势:源网荷储联动如何实现电力系统的 “智慧蝶变”?
  • 如何升级到macOS Tahoe:全面指南与实用步骤
  • 从一开始的网络攻防(六):php反序列化
  • 关于JavaWeb的总结笔记
  • 云原生周刊:K8s 中的后量子密码学
  • 【学习路线】C#企业级开发之路:从基础语法到云原生应用
  • docker 容器学习
  • zabbix企业级分布式监控环境部署
  • 【Prometheus+Grafana篇】监控通过Keepalived实现的MySQL HA高可用架构
  • 在翻译语义相似度和会议摘要相似度评估任务中 ,分类任务 回归任务 生成任务区别
  • 布局AI +文化新赛道,浙江省文化产业投资集团赴景联文科技调研交流
  • uniapp【uni-ui】【vue3】样式覆盖方式记录
  • Git上传与下载GitHub仓库
  • Neo4j 5.x版本的导出与导入数据库
  • 【系统全面】Linux内核原理——基础知识介绍
  • Python-数据库概念-pymysql-元编程-SQLAlchemy-学习笔记
  • 【ASP.NET Core】ASP.NET Core中Redis分布式缓存的应用
  • Python day20 - 特征降维之奇异值分解
  • 隧道代理的动态IP切换机制与实现原理
  • 农村供水智慧化管理系统:从精准监测到智能调度,破解农村用水安全与效率难题
  • 康复器材动静态性能测试台:精准检测,为康复器械安全保驾护航