C#.NET:获取控件的启动/设计师分配的值

问题描述 投票:0回答:1

我想检索设计者为控件分配的值,例如当我使用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;
    }

并且按原样工作,这就是不良方法概念的证明:/

c# .net reflection
1个回答
0
投票

@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

这相当有效,我可以编写进一步的抽象,从而更轻松地重置某些值。我不喜欢必须创建控件的新实例,但是我愿意将其用于此变通方法。但是,绝对欢迎使用更好的方法。

© www.soinside.com 2019 - 2024. All rights reserved.