WPF基于Caliburn.Micro框架的自定义UserControl与父UserControl的MVVM绑定问题排查
我来帮你排查这个绑定问题,你遇到的那些“找不到属性”的错误,核心原因就是自定义UserControl的DataContext设置冲突了。
问题根源分析
你在CustomRepeatButton.xaml里加了这行代码:
DataContext="{Binding RelativeSource={RelativeSource Self}}"
这会把自定义控件自身的DataContext强制设置为它自己,而不是默认继承父控件(ChromeView)的DataContext也就是ChromeViewModel。所以当你在ChromeView里写TextValue="{Binding Adress}"时,绑定系统会去CustomRepeatButton对象里找Adress属性,而不是去ChromeViewModel里找,自然就会抛出绑定路径错误。
解决方案步骤
1. 移除自定义控件的DataContext硬编码
先把CustomRepeatButton.xaml里的这行代码删掉:
DataContext="{Binding RelativeSource={RelativeSource Self}}"
这样自定义控件就会默认继承父控件的DataContext,父控件的绑定就能正确指向ChromeViewModel的属性了。
2. 调整自定义控件内部的绑定指向
因为原来内部控件(TextBox、RepeatButton)的绑定依赖控件自身作为DataContext,现在需要修改为明确指向UserControl自身,有两种常用方式:
方式一:用RelativeSource绑定到父级UserControl
修改CustomRepeatButton.xaml里的Style绑定:
<Style TargetType="TextBox"> <Style.Setters> <!-- 其他Setter保持不变 --> <Setter Property="Text" Value="{Binding TextValue, RelativeSource={RelativeSource AncestorType=local:CustomRepeatButton}, Mode=TwoWay}"/> </Style.Setters> </Style> <Style TargetType="RepeatButton"> <Style.Setters> <!-- 其他Setter保持不变 --> <Setter Property="Interval" Value="{Binding IntervalValue, RelativeSource={RelativeSource AncestorType=local:CustomRepeatButton}, Mode=TwoWay}"/> </Style.Setters> </Style>
方式二:给UserControl命名,用ElementName绑定
先给CustomRepeatButton的根标签加个名字:
<UserControl x:Class="ChromiumWPF.UserControls.CustomRepeatButton" ... x:Name="RootControl">
然后修改内部绑定:
<Style TargetType="TextBox"> <Style.Setters> <!-- 其他Setter保持不变 --> <Setter Property="Text" Value="{Binding TextValue, ElementName=RootControl, Mode=TwoWay}"/> </Style.Setters> </Style> <Style TargetType="RepeatButton"> <Style.Setters> <!-- 其他Setter保持不变 --> <Setter Property="Interval" Value="{Binding IntervalValue, ElementName=RootControl, Mode=TwoWay}"/> </Style.Setters> </Style>
3. 验证依赖属性的绑定行为
你的依赖属性定义基本没问题,不过可以检查下IntervalValueProperty的元数据:你设置了BindsTwoWayByDefault,但其实RepeatButton的Interval是单向绑定也能满足需求,不过这个不影响功能,只是个小优化点。
另外,你在RepeatButton_Click事件里处理值变更时,直接修改TextValue依赖属性即可,因为它是双向绑定,修改后会自动同步到父ViewModel的Adress属性。
测试验证
做完以上修改后,再运行程序,那些绑定错误应该就消失了:
TextValue="{Binding Adress}"会正确绑定到ChromeViewModel的Adress属性IntervalValue="{Binding Test}"会正确读取Test的值设置给RepeatButton的IntervalMaxValue="{Binding MaxV}"也能正确获取父ViewModel的MaxV值
备注:内容来源于stack exchange,提问作者Frenchy

