自定义UserControl的IsEnabled绑定未触发属性Getter问题求助
UserControl绑定属性失效,Getter未触发的问题分析与解决
刚开发自己第一个WPF UserControl就踩了个坑,跟大家分享下问题和解决过程:
问题现象
我做了个IpTextBox控件,绑定到ViewModel的EnableIpSetting属性来控制IsEnabled状态,但发现不管怎么修改ViewModel里的相关值,这个绑定完全没反应——连EnableIpSetting的Getter断点都没触发。但同一页面里的普通TextBox绑定同一个属性却一切正常,状态能跟着属性值变化。
相关代码片段
页面XAML
<luc:IpTextBox x:Name="IpTxtBxIpv4Address" Grid.Row="1" Grid.Column="1" IsEnabled="{Binding VmNicData.EnableIpSetting}" Mode="IPv4Address"/> <TextBox x:Name="TxtBxTest" Grid.Row="1" Grid.Column="2" IsEnabled="{Binding VmNicData.EnableIpSetting}" Text="{Binding VmNicData.IpV4SubnetMask}"/>
ViewModel代码
private bool _ipEnabled; public bool IpEnabled { get => _ipEnabled; set { _ipEnabled = value; OnPropertyChanged(nameof(IpEnabled)); OnPropertyChanged(nameof(EnableIpSetting)); } } private bool _dhcpEnabled; public bool DhcpEnabled { get => _dhcpEnabled; set { _dhcpEnabled = value; OnPropertyChanged(nameof(DhcpEnabled)); OnPropertyChanged(nameof(EnableIpSetting)); } } public bool EnableIpSetting => _ipEnabled && !_dhcpEnabled;
排查过程中的尝试
- 我的
IpTextBox内部就是几个普通TextBox,初始化时在构造函数里写了DataContext = this; - 静态设置
IsEnabled为true或false时,控件内部的TextBox能正常响应状态变化 - 绑定到
EnableIpSetting后彻底失效:哪怕属性初始值是false,控件也没被禁用,给EnableIpSetting加的Getter断点从来没命中 - 对比用的
TxtBxTest绑定同一个属性,断点能正常触发,状态也能跟着变
问题根源与解决方案
折腾了半天终于找到问题了——就是构造函数里的DataContext = this;搞的鬼!
这行代码把UserControl的DataContext强制设为自身,直接破坏了它从父容器继承ViewModel的机制。原本的绑定{Binding VmNicData.EnableIpSetting}是要从父级的DataContext(也就是ViewModel实例)里找属性,但现在UserControl自己成了DataContext,根本没有VmNicData这个属性,绑定自然就失效了,Getter当然不会被调用。
解决方法很简单:删掉构造函数里的DataContext = this;。如果UserControl内部需要绑定自己的属性,改用RelativeSource或者ElementName来指定绑定源,比如:
<!-- 控件内部绑定自身属性的正确写法 --> <TextBox Text="{Binding RelativeSource={RelativeSource AncestorType=luc:IpTextBox}, Path=MyCustomProperty}"/>
这样一来,UserControl就能正常继承父级的DataContext,外部的绑定也能正常工作了。
内容的提问来源于stack exchange,提问作者hquinz
相关产品推荐
相关产品推荐

