我想检索设计者为控件分配的值,例如当我使用TextBox
“ Hello World”设计一个.Text
时,然后在运行时更改.Text
:如何在运行时再次检索字符串“ Hello World”?
到目前为止我的想法:我可以编写一个设置例程,并在其中单独分配这些“默认”值,然后在我想重置这些值时再次调用该方法。缺点:-不那么灵活(无法重置单个控件)-需要为每个实现编写例程-错过了仅在设计器中设置一次值的便利性]
我真的很想要一个静态方法/扩展,它使我能够插入控件并在类设计器中获取为其分配的值。
我开始尝试在扩展库中实现扩展,在该库中创建主Form类的新实例并从中获取值-但这种方法有明显的缺点:-表单类可能具有不同的构造函数签名,例如string[] args
用于带有控制台参数的应用程序;通常,创建未知签名的实例并非易事,也不是一个好主意-这是沉重的方法;根据项目的复杂性,您可能不想每次都想获得Control的设计师分配的值时创建大量实例。-这将执行构造函数中的所有代码
所以我真的希望我可以使用Reflection
或类似的东西来获取设计者分配的值。但是我不知道该如何去寻找。像“ Visual .net获取设计器默认控件值”之类的谷歌搜索没有产生相关结果。
有人能指出我正确的方向吗?
我的测试扩展方法当前看起来像这样:
public static string getDefaultText(this Control c)
{
Form mainForm = Form.ActiveForm; // just a quick easy way to test this
Type t = mainForm.GetType();
var f = Activator.CreateInstance(t);
Control a = ((Form)f).Controls[c.Name]; // unfortunately, .Controls only contains direct children, not all descendants; recursive searching would be needed
return a.Text;
}
并且按原样工作,这就是不良方法概念的证明:/
@Selvin提出了一个好主意:让我从中提出一个初步的答案。
一旦表单使用本地化(在设计时将Localizable
设置为True
),代表设计器在控件中状态的控件版本将存储在应用程序的资源中。这似乎包括所有可设计的属性(Properties面板/窗口中的所有属性)。
使用ComponentResourceManager(实现ResourceManager),我们可以在运行时使用控件的方法ApplyResources将状态再次应用到控件:
public static void resetControl<T>(this T c, string key = "") where T : Control // Using generic approach for the convenience of being able to use the Type T
{
Form f = c.FindForm();
ComponentResourceManager resources = new ComponentResourceManager(f.GetType()); // Manage the resources from our Form class
if (key == "")
{
resources.ApplyResources(c, c.Name); // Simply natively apply all resources
}
else // If we want to reset only one specific property...
{
// rather than trying to get to the data serialized away somewhere, I'm using this work-around
T r = (T)Activator.CreateInstance(c.GetType()); // create a new instance of the Control in question
resources.ApplyResources(r, c.Name);
setAttr(c, key, r.getAttr(key)); // setAttr and getAttr are helper extensions I always have on hand as well
}
}
public static void setAttr(this object o, string key, object val)
{
foreach (PropertyInfo prop in o.GetType().GetProperties())
{
string nam = prop.Name;
if (nam == key)
{
prop.SetValue(o, val);
return;
}
}
}
public static dynamic getAttr(this object o, string key)
{
Type myType = o.GetType();
IList<PropertyInfo> props = new List<PropertyInfo>(myType.GetProperties());
foreach (PropertyInfo prop in props)
{
if (prop.Name == key)
{
return prop.GetValue(o, null).ChangeType(prop.PropertyType);
}
}
return null;
}
用法:
// Reset everything to the Designer state:
textBox1.resetControl();
// Reset only the TextAlign property:
textBox1.resetControl("TextAlign");
// Reset only the Dock property:
textBox1.resetControl("Dock");
// ... etc
这相当有效,我可以编写进一步的抽象,从而更轻松地重置某些值。我不喜欢必须创建控件的新实例,但是我愿意将其用于此变通方法。但是,绝对欢迎使用更好的方法。