[WPF Bug清单]之(2)——RadioButton的IsChecked绑定失效

.NET Framework已经算是一个很易用的库了。可以自动地为我们做很多事情,而且大都做得还不错。但是自动完成的事情很可能会有隐患,因为Framework本身是并不了解业务逻辑的。它自动完成的事情,可能会给我们帮倒忙。

 

RadioButton就是其中一个。

 

先来从设置值的角度介绍一下WPF里的Dependency Property(以下简称DP)。在WPF里控制一个控件的DP,有太多的方式。可以用Style,可以用Animation,可以用Data Binding,可以用Trigger,还有最基本直接赋值。控件会综合上面各个方面的值,其及优先级等因素来决定一个DP的最终的值是多少。关于这方面的更多的知识可以参考雨痕关于DP的文章MSDN。(不过不确定MSDN上有没有有关DP设值优先级的系统的介绍哦。)

 

多数的控件不会自动的更改自己的某个属性的值。但是总有一些例外。RadioButton就是其中一个。它自动设置什么值了?答案是IsChecked属性。RadioButton的特点是一组RadioButton只有一个被选中。当一个RadioButton被选中的时候,其它所有的RadioButton就会被自动地设置IsChecked属性为False

 

问题来了,设置一个属性的方法那么多,它自己自动设置这个属性的时候,应该用什么方法呢?这个问题早在.NET 3.0时就已经有人发现,并在微软的论坛上讨论过。MSFTSam Bent也承认了这个Bug的存在。但问题就在于,无论RadioButton用哪种现有的方法去使得IsChecked属性为False,“总会有些人不高兴”。3.0RadioButton的自动,会让StyleTemplate的值失效;在3.5中,Fix3.0中的这个Bug,但是却导致Binding失效。

 

经过笔者验证,在.NET 3.5 SP1中使用了与3.5相同的逻辑,即使Binding失效。下面我们将用一个“为微软选CEO”的示例程序进行验证。

 

首先定义一个Person类,如下:

 

ContractedBlock.gif ExpandedBlockStart.gif Person
 1using System.ComponentModel;
 2using System.Diagnostics;
 3
 4namespace BindingRadioButton.Model
 5ExpandedBlockStart.gifContractedBlock.gif{
 6ExpandedSubBlockStart.gifContractedSubBlock.gif    /**//// <summary>
 7    /// 
 8    /// </summary>

 9    public class Person : INotifyPropertyChanged
10ExpandedSubBlockStart.gifContractedSubBlock.gif    {
11ContractedSubBlock.gifExpandedSubBlockStart.gif        Private Fields#region Private Fields
12
13        private bool isCeo;
14        private string name;
15
16        #endregion

17
18ContractedSubBlock.gifExpandedSubBlockStart.gif        Public Properties#region Public Properties
19
20ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
21        /// 
22        /// </summary>

23        public bool IsCeo
24ExpandedSubBlockStart.gifContractedSubBlock.gif        {
25ExpandedSubBlockStart.gifContractedSubBlock.gif            get return isCeo; }
26            set
27ExpandedSubBlockStart.gifContractedSubBlock.gif            {
28                if (value != isCeo)
29ExpandedSubBlockStart.gifContractedSubBlock.gif                {
30                    isCeo = value;
31                    OnPropertyChanged("IsCeo");
32                }

33            }

34        }

35
36ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
37        /// 
38        /// </summary>

39        public string Name
40ExpandedSubBlockStart.gifContractedSubBlock.gif        {
41ExpandedSubBlockStart.gifContractedSubBlock.gif            get return name; }
42            set
43ExpandedSubBlockStart.gifContractedSubBlock.gif            {
44                if (value != name)
45ExpandedSubBlockStart.gifContractedSubBlock.gif                {
46                    name = value;
47                    OnPropertyChanged("Name");
48                }

49            }

50        }

51
52        #endregion

53
54ContractedSubBlock.gifExpandedSubBlockStart.gif        INotifyPropertyChanged Members#region INotifyPropertyChanged Members
55
56ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
57        /// 
58        /// </summary>

59        public event PropertyChangedEventHandler PropertyChanged;
60
61        #endregion

62
63        protected virtual void OnPropertyChanged(string propertyName)
64ExpandedSubBlockStart.gifContractedSubBlock.gif        {
65            PropertyChangedEventHandler temp = PropertyChanged;
66            if (temp != null)
67ExpandedSubBlockStart.gifContractedSubBlock.gif            {
68                temp(thisnew PropertyChangedEventArgs(propertyName));
69                Trace.WriteLine(string.Format("{0} {1} CEO\n", Name, IsCeo ? "is" : "is not"));
70            }

71        }

72    }

73}

74

 

由于实现了INotifyPropertyChanged接口,这个类的实例可以被Binding。我们在PropertyChanged的时候,输出一条信息,说明当前的CEO是谁。注意里面IsCeoFalse的时候也会输出消息哦。说明谁被撤职了。

 

然后建立UI如下。

 

ContractedBlock.gif ExpandedBlockStart.gif UI
 1<Window x:Class="BindingRadioButton.DemoWindow"
 2    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4    xmlns:model="clr-namespace:BindingRadioButton.Model"
 5    Title="RadioButton Binding Lost"
 6    Height="300" Width="300">
 7    <Window.Resources>
 8        <model:Person x:Key="First" Name="Bill Gates"/>
 9        <model:Person x:Key="Second" Name="Steve Ballmer"/>
10    </Window.Resources>
11    <DockPanel Margin="12">
12        <GroupBox DockPanel.Dock="Top"
13                  Header="Select a CEO for MSFT"
14                  Padding="9" Margin="0,0,0,12">
15            <StackPanel>
16                <RadioButton DataContext="{StaticResource First}"
17                             IsChecked="{Binding IsCeo}"
18                             Content="{Binding Name}"
19                             GroupName="ceo" Margin="0,0,0,5"/>
20                <RadioButton DataContext="{StaticResource Second}"
21                             IsChecked="{Binding IsCeo}"
22                             Content="{Binding Name}"
23                             GroupName="ceo"/>
24            </StackPanel>
25        </GroupBox>
26
27        <Label DockPanel.Dock="Top" Content="Message:"
28               Padding="0" Margin="0,0,0,5"/>
29        <TextBox Name="messageBox"/>
30    </DockPanel>
31</Window>

 

 

其中的messageBox用于显示Trace输出的消息。运行结果如下。

 

1. 刚启动

 

现在MSFT没有CEO,我们点Steve Ballmer选择一个之后如图2

 

2. 选择一个

 

然后选择另一个作为CEO,之后如图3

 

3. 选择另一个

 

有心的读者应该已经可以看出,到这里已经可以证明有一个绑定已经失效了。不过我们继续用更明显的方式继续点点。

再选回Steve Ballmer,如图4

 

4. 再选择一个

 

结果再没有消息出来了。很明显,Binding失效了。

根据“小明”同学的回复,此BUG已经在.NET4.0中修复。

同系列的其它文章:

[WPF Bug清单]()与之(1)——可以多选的单选ListBox

[WPF Bug清单](3)——暗中创建文件的打开文件对话框

[WPF Bug清单](4)——点击RadioButton的空白没有反应

[WPF Bug清单](5)——隐藏模态对话框后变成非模态

[WPF Bug清单](6)——ButtonIsCancel属性失效

[WPF Bug清单](7)——顽固的Error Template

[WPF Bug清单](8)——RowDefinitionMaxHeight在一定条件下失效

[WPF Bug清单](9)——消失的光标

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值