如何在WPF的ListBox中根据数据自定义Item的位置?附答案
话说,包包想在游戏大厅里实现只操作数据源就能更新绑定控件的需求。OK,你一定会说,用ListBox。没错,ListBox就是干这个用的:
以下是xaml和后台代码:
<UserControl x:Class="TestDeskBindingWpfApplication.PaneDesk" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:TestDeskBindingWpfApplication" Height="160" Width="160"> <UserControl.Resources> <Style TargetType="{x:Type Image}" x:Key="desk" /> <local:ImageConverter x:Key="imageConverter" /> <local:HandConverter x:Key="handConverter" /> <local:LeftConverter x:Key="leftConverter" /> <local:TopConverter x:Key="topConverter" /> <DataTemplate DataType="{x:Type local:UserInfo}"> <TextBlock> <Image Canvas.Left="60" Canvas.Top="3" Name="chair" Source="{Binding Path=ImageIndex, Converter={StaticResource imageConverter}, Mode=TwoWay, NotifyOnTargetUpdated=True}" /> <Image Canvas.Left="86" Canvas.Top="53" Name="hand" Source="Img/hand.gif" Visibility="{Binding Path=IsPrepareOK, Converter={StaticResource handConverter}, Mode=TwoWay, NotifyOnTargetUpdated=True}" /> <Label Name="lblUser" Width="54" Canvas.Left="{Binding Path=DeskPosition, Converter={StaticResource leftConverter}}" Canvas.Top="{Binding Path=DeskPosition, Converter={StaticResource topConverter}}" Content="{Binding Path=UserName, Mode=TwoWay, NotifyOnTargetUpdated=True}" /> </TextBlock> </DataTemplate> </UserControl.Resources> <Canvas Background="#FF28699E"> <ListBox Canvas.Left="0" Canvas.Top="0" Height="160" x:Name="r1" Width="160" /> </Canvas> </UserControl>
相应数据源代码:
public ObservableCollection<UserInfo> Users = new ObservableCollection<UserInfo>();UserInfo user = null; user = new UserInfo { UserId = 2, UserName = "kitty", DeskId = 1, DeskPosition = 1, ImageIndex = 4, IsPrepareOK = true }; Users.Add(user); user = new UserInfo { UserId = 1, UserName = "jax", DeskId = 1, DeskPosition = 2, ImageIndex = 3 }; Users.Add(user); user = new UserInfo { UserId = 4, UserName = "dx", DeskId = 1, DeskPosition = 3, ImageIndex = 1 }; Users.Add(user); user = new UserInfo { UserId = 3, UserName = "jeffrey", DeskId = 1, DeskPosition = 4, ImageIndex = 4 }; Users.Add(user); r1.ItemsSource = Users;
这样做的好处是,以后我只需要Users.Add(newUser)或Users.Remove(oldUser)就可以同时控制桌子上显示的用户了。
但是,我要说,我想在桌子里实现这样的效果:
就是说,对号入座,将ListBox中的每个Item都能自定义它的定位,但遗憾的是,ListBox中的Item要么是横向排列的,要么是纵向的,不支持随意定位。
本文代码下载:https://files.cnblogs.com/Jax/TestDeskBindingWpfApplication.rar
这个技术困扰我两天,请教了很多人,都不得要领。请园子里的WPF兄弟们研究一下吧,给出解决方案来。注意,Users数据结构不能修改。你可以随便定义DP,或自定义Panel+自定义Control,但要保证我只需要Users.Add(newUser)或Users.Remove(oldUser)就可以修改用户即显示,而无需多余操作。
答案:
正当我心灰意冷之即,约mm去Tom Bear放松一下,在地铁上我已经想好了要熬通宵重新设计数据结构以避开这个难题,SeanYao帮我发来了一个最简单的Demo,仅修改了XAML,如下所示:

感谢Sean的帮助,这个答案是最合我意的。
感谢 YoHan和winter-cn的热心参与。winter-cn的答案与上述大同小异,但老兄你是否发现,点击第一个Item会有一个底色背景(因为仍然继承ListBox而延续了SelectItem的原因);YoHan的Demo做的有点复杂了,hoho,但还是感谢你花那么多时间写那么多代码做出相同的效果来。
就不感谢周银辉、赖仪灵和颗粒宁博爱了哦!嘿嘿。
本贴正式结贴!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?