Welcome

首页 / 软件开发 / .NET编程技术 / WPF Bug清单之(2)——RadioButton的IsChecked绑定失效

WPF Bug清单之(2)——RadioButton的IsChecked绑定失效2011-01-25 博客园 南柯之石.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时就已经有人发现,并在微软的论坛上讨论过。MSFT的Sam Bent也承认了这个Bug的存在。但问题就在于,无论RadioButton用哪种现有的方法去使得IsChecked属性为False,“总会有些人不高兴”。3.0里RadioButton的自动,会让Style和Template的值失效;在3.5中,Fix了3.0中的这个Bug,但是却导致Binding失效。

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

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

Person

1using System.ComponentModel;
2using System.Diagnostics;
3
4namespace BindingRadioButton.Model
5{
6 /**//// <summary>
7 ///
8 /// </summary>
9 public class Person : INotifyPropertyChanged
10 {
11 Private Fields#region Private Fields
12
13 private bool isCeo;
14 private string name;
15
16 #endregion
17
18 Public Properties#region Public Properties
19
20 /**//// <summary>
21 ///
22 /// </summary>
23 public bool IsCeo
24 {
25 get { return isCeo; }
26 set
27 {
28 if (value != isCeo)
29 {
30 isCeo = value;
31 OnPropertyChanged("IsCeo");
32 }
33 }
34 }
35
36 /**//// <summary>
37 ///
38 /// </summary>
39 public string Name
40 {
41 get { return name; }
42 set
43 {
44 if (value != name)
45 {
46 name = value;
47 OnPropertyChanged("Name");
48 }
49 }
50 }
51
52 #endregion
53
54 INotifyPropertyChanged Members#region INotifyPropertyChanged Members
55
56 /**//// <summary>
57 ///
58 /// </summary>
59 public event PropertyChangedEventHandler PropertyChanged;
60
61 #endregion
62
63 protected virtual void OnPropertyChanged(string propertyName)
64 {
65 PropertyChangedEventHandler temp = PropertyChanged;
66 if (temp != null)
67 {
68 temp(this, new PropertyChangedEventArgs(propertyName));
69 Trace.WriteLine(string.Format("{0} {1} CEOn", Name, IsCeo ? "is" : "is not"));
70 }
71 }
72 }
73}
74