C # .NET: Получить запускаемые / назначенные дизайнером значения элементов управления - PullRequest
0 голосов
/ 23 декабря 2019

Я хочу получить назначенные конструктором значения элементов управления, например, когда я спроектировал TextBox с .Text «Hello World», а затем изменить .Text во время выполнения: как я могу получить строку «Hello»Мир снова во время выполнения?

Мои мысли пока таковы: я могу написать процедуру настройки и назначить эти значения «по умолчанию» там в одиночку, и снова вызывать этот метод, когда захочу сбросить значения. Минусы:
- Не такой гибкий (нет способа сброса отдельных элементов управления)
- потребуется написать подпрограмму для каждой реализации
- упущено из-за удобства простой установки значений один раз в конструкторе

Мне бы очень хотелось статический метод / расширение, которое позволило бы мне подключить мой элемент управления и получить значения, назначенные ему в конструкторе моего класса.

Я начал пытаться реализовать расширение в своем расширениибиблиотека, в которой я создаю новый экземпляр основного класса Form и извлекаю значение оттуда - но у этого подхода есть очевидные недостатки:
- Form Class может иметь разные сигнатуры конструктора, например string[] args для приложений с консольными аргументами;создание экземпляров неизвестных подписей не является тривиальной или хорошей идеей в целом
- Это тяжелый подход;в зависимости от сложности проекта, вам может не потребоваться создавать стопки экземпляров каждый раз, когда вы хотите получить назначенное конструктором значение элемента управления.
- это выполнит любой код в конструкторе

Поэтому я очень надеюсь, что смогу использовать Reflection или что-то подобное, чтобы получить значения, назначенные дизайнером.
Но я не знаю, как искать это;поиск в Google таких вещей, как «Visual .Net Get Designer Control по умолчанию», не дал соответствующих результатов.

Может кто-нибудь указать мне правильное направление?

Мой метод расширения теста в настоящее время выглядит примерно так:

    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;
    }

и работает таким, какой он есть, то есть доказательством концепции плохого подхода: /

1 Ответ

0 голосов
/ 23 декабря 2019

@ Selvin прокомментировал хорошую идею: позвольте мне сформулировать предварительный обходной путь.

Как только форма использует Локализация (установите Localizable на True во время разработки), версия элемента управления, представляющая его состояние в конструкторе, сохраняется в приложении Ресурсы . Кажется, сюда входят все проектируемые свойства (все в панели / окне Свойства ) ( Редактировать: очевидно, не ).

Использование 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

Это работает достаточно хорошо, и я могу написать дополнительные абстракции, облегчающие процесс сброса определенных значений.
Мне не нравится создавать новый экземпляр элемента управления, но я хочу жить с этим дляэто обходной путь. Тем не менее, лучшие подходы определенно приветствуются.

Обновление: недостатки

  • Похоже, что пустое значение .Text из Designer не будет перезаписывать непустое значение .Text с использованием ApplyResources, похоже на то.
    • Однако при использовании экземпляра прокси-элемента управления, как в случае предоставления «Текст» в качестве ключевой строки в моем методе расширения выше, это все еще работает
  • Это выглядит такэто не работает с большинством элементов управления. До сих пор тестирование работало только на TextBoxes, Labels и CheckBoxes со свойством .Text, но не свойством .Checked CheckBox
  • Попытка сброса NumericUpDown .Text (например,потому что вы ковер-бомбардировку всего с сбросом «Текст» для того, чтобы сбросить его для тех, кто имеет соответствующий .Text) установит его .Value 0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...