Могу ли я иметь тип "класс" в С#?

Мне интересно, можно ли что-то сделать. У меня есть функция, которая читает xml файл и добавляет элементы управления в форму, основанную на содержимом файла. Xml node, как это, создаст его:

<Button Top="300" Left="100">Automatic</Button>

У меня есть функция, которая сохраняет элементы управления обратно в xml файл, если я добавил их в режим редактирования. Он работает, но мне интересно, есть ли более простой способ. В настоящее время у меня есть код, который выглядит так, чтобы создать экземпляр каждого элемента управления:

            switch (xmlchild.Name)
            {
                // Create a new control whose type is specified.
                case "Button":
                    c = new Button();
                    break;
                case "Label":
                    c = new Label();
                    break;
                default:
                    c = null;
                    break;
            }

Но, когда я хочу использовать больше типов элементов управления, мне нужно будет продолжать добавлять случаи переключения. Могу ли я сделать то, что просто возьмет текст и добавить элемент управления этого типа? Буду признателен за любую обратную связь!

Спасибо!

Ответ 1

Если вы контролируете содержимое XML файла, тогда да. Вы можете использовать:

string fullNameSpace = "System.Windows.Controls.";
Type controlType = Type.GetType( fullNameSpace + xmlchild.Name );
if( controlType != null )
{
  // get default constructor...
  ConstructorInfo ctor = controlType.GetConstructor(Type.EmptyTypes);
  object control = ctor.Invoke(null);
}

Вы также можете использовать класс Activator для его очистки немного:

object control = Activator.CreateInstance( "System.Windows.Presentation", 
                                           xmlchild.Name );

В качестве альтернативы, если вы можете создать допустимый файл XAML, вы можете использовать XamlReader для восстановления дерева управления.

Ответ 2

Вы можете использовать какое-то соглашение, чтобы сохранить себе какой-то код. В принципе, используйте отражение, чтобы создать экземпляр любого элемента управления, который вы хотите, передавая код из XML. Что-то вроде:

Activator.CreateInstance(xmlchild.Name, ...)

Просто заполните правильные биты, и многое из этого кода исчезнет.

Ответ 3

Похоже, вы ищете что-то вроде Generics.

Вы можете сделать что-то следующее:

public static class ControlFactory
{
    public static T CreateControl<T>() where T : Type, new()
    {
        return new T();
    }
}

Я еще не тестировал этот код, поэтому обновляю его при проверке.

Ответ 4

В первую очередь ознакомьтесь с классом Activator. Затем вы можете сохранить имя типа элемента управления как атрибут в файле xml и использовать класс Activator для создания экземпляров на основе значения, хранящегося в атрибуте из текущего элемента xml (type = "fullTypeName" ).

Кроме того, если дело доходит до свойств, вы можете рассмотреть отражение, чтобы установить свойства на созданные экземпляры на основе имени атрибута (т.е. у вас есть экземпляр элемента управления, созданного с классом Activator, и вы назначаете vale из атрибута Top в xml к свойству Top из созданного экземпляра, который вы можете получить/установить с помощью отражения).

Ответ 5

Можно использовать Reflection, как описано другими, для конструирования элемента управления непосредственно из его имени. Однако этот дизайн довольно хрупкий и может также представлять проблемы безопасности, если XML файл является общедоступным, поскольку произвольные типы управления могут быть созданы во время выполнения на основе текста в файле. Это может не беспокоить ваше конкретное приложение.

Я бы предпочел дизайн с помощью Dictionary<string, Func<Control>>, где у вас есть код, который регистрирует обратный вызов, который создает элемент управления для каждого имени. Это дает вам дополнительную гибкость (вы можете динамически менять методы построения управления или комбинировать доступные элементы управления из нескольких источников), а также может выглядеть более чистым (коммутатор заменяется несколькими "регистрационными" вызовами, а фактическая конструкция разбивается на отдельные методы или (в простом случае) в виде лямбда-выражения). Это также обеспечивает обратную совместимость, если вы замените TextBox в своем приложении MyImprovedTextBox и хотите, чтобы предыдущие файлы конфигурации использовали улучшенную версию.