简介
本文介绍了控制,支持简化类型之间的RadioButton控制面板和枚举属性的数据绑定。
背景
。NET Windows窗体我曾参与过的项目,piddling的困扰,我比任何其他的问题是缺乏支持RadioButton的处理。当然,你可以粘在一个小组或GroupBox的RadioButtons一堆,将请执行Windows窗体上设置一个最小的分组行为,使选择在任何一个时间只有一个无线电。问题arisesnbsp; younbsp;时需要知道是哪个RadioButton的检查。无论是小组也没有的GroupBox表面会告诉你这一个事件或财产,它留给你的,提供一个单一的RadioButton组中的每一个的事件处理程序。不用说,这个可怜的支持,很容易绑定RadioButton组是前功尽弃,但一个白日梦。
其他人更聪明,比我已经递上了解决这个问题。最好的可能是{A},模拟相应的ASP.NET控件。虽然好,该解决方案达成我严重矫枉过正。我想要的是一个简单的解决方案,使用标准的单选按钮 - 自定义面板控制,提供双向数据绑定到业务对象的枚举类型的属性,以及作为一个单一的事件通知,指示当前选择改变时。我并不需要一个quot; codequot;的做法,必然 - 只是一个方法,大大简化了意大利面条式的代码,不可避免地带来的RadioButton处理。
我的解决方案,RadioPanel,需要最少的布线:极少数的设计师设置,加上一行代码。在应用程序需要两个,三个或更多的RadioButton板,这个法术在代码中的相当大的减少。使用代码
图1显示了简单的业务对象代表的船只。我们的船有一个Type属性,标志着由VesselType枚举:public enum VesselType
{
Cargo = 0,
Container,
BulkCarrier,
Reefer,
Passenger,
Tanker
}
我们可以使用RadioPanel面板包含这些选项的每一个按钮创建一个新形式。拉断我们的约束力,我们利用的事实,在Windows Forms 2.0中的每一个控件公开一个标签属性接受任意数据。每个RadioButton填充其相应的选项,在我们的VesselType枚举数值,我们将使用Tag属性。由于"Cargoquot; VesselType在第一个选项,我们分配rbVesselTypeCargo.Tag值为0。接着,我们rbVesselTypeContainer.Tag = 1,所以我们所有的RadioButton选项。
RadioPanel支持名为ValueMember一个属性,表明我们希望绑定到的属性。我们给这个价值的quot; Type.quot;最后,我们窗体的Load事件里面,我们创建我们的业务对象的一个实例,并分配到DataSource属性的RadioPanel:{C}
,您可以运行此应用程序,并使用调试器来验证Vessel.Type财产更新,当您选择一个新的类型船只。您可以使用",设定Valuequot按钮的形式,以验证绑定是双向的:当船舶更新对象,所以是RadioButton的选择。兴趣点
的代码,驾驶这使得相当简单使用。NET的功能强大的反射API。反射使您能够在运行时对象的属性,方法和事件。这是被称为后期绑定,而不是在编译过程中执行的早期绑定:而不是在代码中指定你的属性和方法调用静态,你可以获取一个通用的参考的对象,并调用其属性和方法,使用字符串参数。RadioPanel踢关闭程序,一旦检测到您已分配有效的ValueMember和DataSource属性。 DataSource属性使用Object.GetType()来获取数据源的基础类型的引用。然后,它采用Type.GetInterface()方法来发现我们的数据源是否支持INotifyPropertyChanged的。如果是这样,它使用Type.GetEvent()得到一个PropertyChanged事件的处理,并建立了一个侦听器。Type iface = _dataSource.GetType().GetInterface("INotifyPropertyChanged");
if (iface != null)
{
_ei = iface.GetEvent("PropertyChanged");
if (_ei != null) // which would be weird if it did...
{
_ei.AddEventHandler(_dataSource, _pceh);
}
}
取得ValueMember属性收益以类似的方式值的代码。 Type.GetProperty()方法返回PropertyInfo类型的对象,它支持读取和使用GetValue的基本财产的价值()的SetValue()方法,分别设置。这是相当简单的代码,所以我不会在这里重现;看到完整的项目细节。
我们怎么知道什么时候选择一个RadioButton已经改变?很简单:我们一直在倾听每个RadioButton的CheckedChanged事件,我们作为我们的切入点事件接线面板中的父ControlAdded方法:protected override void OnControlAdded(ControlEventArgs e)
{
base.OnControlAdded(e);
if (e.Control is RadioButton)
{
RadioButton rb = (RadioButton)e.Control;
rb.CheckedChanged += rb_CheckedChanged;
}
}
rb_CheckedChanged然后射击RadioButtonSelectionChanged事件,以及我们的DataSource设置新选定的值。注意,我们使用一个布尔标志,以防止反射代码,这将产生处理PropertyChanged的通知。也许最"; magicalquot;这个代码的一部分,是Enum.Parse()调用,RadioButton.Tag VesselType枚举的一个实例中发现的整数转换。void rb_CheckedChanged(object sender, EventArgs e)
{
if (_dataSource != null)
{
int nSetting = 0;
if (sender is RadioButton)
{
RadioButton rbSender = (RadioButton)sender;
// Fire the RadioButtonChanged event.
FireRadioSelectionChanged(rbSender);
if (rbSender.Tag == null)
{
throw new InvalidOperationException("RadioButton " + rbSender.Name +
" does not have its Tag property set to a valid enum integer value.");
}
if (!Int32.TryParse(rbSender.Tag.ToString(), out nSetting))
{
throw new InvalidOperationException("RadioButton " + rbSender.Name +
" does not have its Tag property set to a valid enum integer value.");
}
PropertyInfo pi =
(PropertyInfo)_dataSource.GetType().GetProperty(_valueMember);
if (pi != null)
{
// Convert the int into its corresponding enum.
// pi.PropertyType represents the enum's type.
object parsedEnum;
try
{
parsedEnum = Enum.Parse(pi.PropertyType, nSetting.ToString());
}
catch (Exception ex)
{
throw new InvalidOperationException
("Could not convert RadioButton.Tag value into an enum.", ex);
}
// Stop listening to property changes while we change the property
// - otherwise, stack overflow.
_processPropertyChange = false;
pi.SetValue(_dataSource, parsedEnum, null);
_processPropertyChange = true;
}
}
}
}
对于大多数用途,但是,你会不会担心这quot;下curtainquot,布线,只需添加到您的控制库的控制,并用它来你的心脏的内容。我想你会发现它很好地收拾你的Windows窗体界面代码。历史2007年8月28日:战后初期