Skip to content

WPF 调试因为对象不同而绑定失效问题

Updated: at 12:43,Created: at 07:16

在 WPF 使用绑定的时候,发现绑定不上,也许是因为绑定的对象不是当前作用的对象的原因。也许是绑定错了对象,或者对象被变更了。本文来告诉大家这个调试思路和方法

使用一个简单的例子来告诉大家,这样比较直观

我有一个简单的应用,这个应用的字符串显示绑定了一个 ToggleButton 也就是下图的写着 点击 的按钮

在 ToggleButton 的 IsChecked 变化的时候,将会自动更改 TextBlock 的内容

大概的效果如下图

界面的代码大概如下

<Window.Resources>
<local:FooConverter x:Key="FooConverter" />
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock x:Name="TextBlock" HorizontalAlignment="Center" VerticalAlignment="Center"
Text="{Binding ElementName=ToggleButton,Path=IsChecked,Converter={StaticResource FooConverter}}" />
<StackPanel x:Name="Panel" Grid.Row="1" Orientation="Horizontal">
<ToggleButton x:Name="ToggleButton" Margin="10,10,10,10" Content="点击" Click="ToggleButton_OnClick" />
<Button Margin="10,10,10,10" Content="不要点击这里" Click="Button_OnClick" />
</StackPanel>
</Grid>

而 FooConverter 的代码如下

public class FooConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is true)
{
return "林德熙是逗比";
}
return "林德熙不是逗比";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

细心的小伙伴可以看到在上面动态图片的点击里面,在点击了 不要点击这里 按钮之后,再次点击 ToggleButton 时,就不会更改 TextBlock 的内容了

看起来就是 TextBlock 的绑定失效了

其中的一个调试思路就是判断绑定的对象是否更改,在后台代码里面,可以在对象状态变更的时候,如 ToggleButton 的 Click 事件,进行绑定对象的判断

通过以下代码可以读取某个对象的某个依赖属性的绑定表达式的值

private void ToggleButton_OnClick(object sender, RoutedEventArgs e)
{
var bindingExpression = TextBlock.GetBindingExpression(TextBlock.TextProperty);
}

如果读取不到绑定表达式,那么可以证明这个绑定表达式没替换了,如后台代码给依赖属性赋值,如以下代码

TextBlock.Text = "123";

此时的赋值将会替换掉原先的绑定表达式,因此尝试获取绑定表达式将会返回空的值

而如果在获取绑定表达式的时候,可以看到有值,那么也许是绑定的对象不对,可以通过 bindingExpression.DataItem 进行判断,如下面代码

private void ToggleButton_OnClick(object sender, RoutedEventArgs e)
{
var bindingExpression = TextBlock.GetBindingExpression(TextBlock.TextProperty);
var toggleButton = (ToggleButton) sender;
if (ReferenceEquals(toggleButton, bindingExpression.DataItem))
{
}
}

此时如果作用的 ToggleButton 和绑定表达式的绑定对象是相同的,那么 ReferenceEquals 将会进入分支

在实际调试的时候,可以看到默认都会进入 ReferenceEquals 返回 true 的分支。而在点击了 不要点击这里 按钮之后,将不会进入 ReferenceEquals 返回 true 的分支

这就证明了绑定表达式绑定的对象更改了

而为什么对象更改了,在这个例子里面是谁更改了 ToggleButton 对象,这就需要其他调试手段了。如本文的更改实际是逗比的代码,在 不要点击这里 按钮的点击事件里面写了下面代码

private void Button_OnClick(object sender, RoutedEventArgs e)
{
var fakeToggleButton = new ToggleButton()
{
Margin = new Thickness(10),
Content = "点击"
}.Do(button => button.Click += ToggleButton_OnClick);
Panel.Children.RemoveAt(0);
Panel.Children.Insert(0, fakeToggleButton);
}

本文代码放在github欢迎小伙伴访问


知识共享许可协议

原文链接: http://blog.lindexi.com/post/WPF-%E8%B0%83%E8%AF%95%E5%9B%A0%E4%B8%BA%E5%AF%B9%E8%B1%A1%E4%B8%8D%E5%90%8C%E8%80%8C%E7%BB%91%E5%AE%9A%E5%A4%B1%E6%95%88%E9%97%AE%E9%A2%98

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。 欢迎转载、使用、重新发布,但务必保留文章署名 林德熙 (包含链接: https://blog.lindexi.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我 联系