我创建了简单的自定义控件 - 派生自Component类:
public partial class TrialChecker : Component
{
private int _trialDays;
public int TrialDays
{
get { return _trialDays; }
set { _trialDays = value;}
}
public TrialChecker()
{
InitializeComponent();
MessageBox.Show(TrialDays.ToString());
}
public int GetTrialDays()
{
return _trialDays;
}
}
此控件将用于在我的应用程序中实现试用功能。应用程序(在启动之前)应检查试用剩余天数并显示包含试用剩余天数的通知对话框和文本框以写入解锁密钥。
但是我希望在使用此控件时尽可能减少所需的代码量。因此,我的想法是将试验检查代码放在我的控件中 - 并且 - 在创建控件之后,它应该显示剩余的天数。
试用期(TrialDays属性)是在用户设计器上设置的,应该只使用afeter控件创建。正如您所看到的,我尝试将其置于构造函数中但它不起作用,因为在将TrialDays设置为在用户设计器中输入的valuje之前调用构造函数。 MessageBox始终显示默认值0。
没有任何OnLoad或OnCreate事件可以覆盖。那么,如何使用在设计器中输入的值自动检查试用状态?
答案 0 :(得分:4)
Component类非常简单,它只是提供了一种在设计时在窗体上托管组件的方法,使用Properties窗口可以访问其属性。但它没有显着的有用事件,使用组件需要表单中的显式代码。像OpenFormDialog一样,在调用ShowDialog()方法之前没有任何反应。
构造函数是可用的,但遗憾的是它运行得太早。 DesignMode属性告诉您组件是否在设计时运行但在构造函数时尚未设置。您需要延迟代码,这很困难,因为以后没有其他方法或事件可以运行。
解决方案是使用您删除组件的表单的事件。像Load事件一样。这需要一些令人头晕目眩的代码来诱使设计师告诉你有关表格的信息。 ErrorProvider组件使用该技术,它需要公开ContainerControl类型的属性并覆盖Site属性setter。像这样:
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Windows.Forms;
public partial class Component1 : Component {
private ContainerControl parent;
[Browsable(false)]
public ContainerControl ContainerControl {
get { return parent; }
set {
if (parent == null) {
var form = value.FindForm();
if (form != null) form.Load += new EventHandler(form_Load);
}
parent = value;
}
}
public override ISite Site {
set {
// Runs at design time, ensures designer initializes ContainerControl
base.Site = value;
if (value == null) return;
IDesignerHost service = value.GetService(typeof(IDesignerHost)) as IDesignerHost;
if (service == null) return;
IComponent rootComponent = service.RootComponent;
this.ContainerControl = rootComponent as ContainerControl;
}
}
void form_Load(object sender, EventArgs e) {
if (!this.DesignMode) {
MessageBox.Show("Trial");
}
}
}
代码是不可思议的,但你可以非常肯定它是可靠和稳定的,因为这是ErrorProvider组件使用的。确保在试用期结束时调用Environment.Exit(),异常不能正常工作。