WPF自定义用户控件中ListBox的ItemTemplate如何正确设置绑定上下文
问题原因
你当前的绑定逻辑有两个核心问题:
- 你在使用控件时给
MainLabel赋值用了{Binding NameShort1},这个绑定的上下文是当前窗口的WindowEditCaseVM,而NameShort1是Participants集合中单个元素的属性,自然会报找不到属性的错误。 - 内部
ItemTemplate里的绑定现在取的是UCListBox的MainLabel属性值,而不是把MainLabel作为属性名去绑定列表项的对应属性。
解决方案
我们采用传属性名+动态取值的方式实现,改动最小兼容性最好:
第一步:添加属性取值转换器
新建一个转换器类,用来根据属性名从列表项对象中反射取值:
public class PropertyGetterConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value == null || parameter is not string propName || string.IsNullOrEmpty(propName)) return null; var prop = value.GetType().GetProperty(propName); return prop?.GetValue(value)?.ToString(); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
在你的资源字典中注册这个转换器:
<Application.Resources> <local:PropertyGetterConverter x:Key="PropertyGetterConverter"/> </Application.Resources>
第二步:修改自定义控件的XAML代码
调整ItemTemplate里的TextBlock绑定逻辑:
<ListBox ItemsSource="{Binding ItemsSource, RelativeSource={RelativeSource AncestorType=local:UCListBox}}" SelectedItem="{Binding SelectedItem, RelativeSource={RelativeSource AncestorType=local:UCListBox}}" > <ListBox.ItemTemplate> <DataTemplate> <StackPanel> <TextBlock Tag="{Binding MainLabel, RelativeSource={RelativeSource AncestorType=local:UCListBox}}"> <TextBlock.Text> <Binding Path="." Converter="{StaticResource PropertyGetterConverter}" ConverterParameter="{Binding Tag, RelativeSource={RelativeSource Self}}"/> </TextBlock.Text> </TextBlock> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox>
第三步:修改控件的使用代码
不需要再给MainLabel加Binding语法,直接传属性名字符串即可:
<local:UCListBox ItemsSource="{Binding Participants}" SelectedItem="{Binding SelectedParticipant}" MainLabel="NameShort1" />
如果需要支持多绑定、复杂路径的场景,可以把MainLabel的类型改为BindingBase,在MainLabel的依赖属性变更回调里动态生成DataTemplate即可,灵活性更高。
内容的提问来源于stack exchange,提问作者Igor Cheglakov
相关产品推荐
相关产品推荐

