Добрый день.
Хочу с помощью PropertyGrid реализовать изменение и сохранение настроек программы. Но параметры заранее не известны и будут иметь след структуру:
AppConfig
— Property1
— Property2
— // —
— Property N
DataBaseConfig
— DBProfile 1
— Property1
— Property2
— // —
— Property N
— DBProfile 2
— Property1
— Property2
— // —
— Property N
— // —
— DBProfile M
Помогите реализовать подобное.
17.05.10 23:34: Перенесено модератором из '.NET' — Хитрик Денис
Помню, делал подобное так: генерировал исходный код класса (со всеми необходимыми атрибутами у свойств), затем компилировал и загружал в память (с помощью CSharpCodeProvider), создавал экземпляр объекта (с помощью Reflection) и передавал PropertyGrid'у.
Здравствуйте, lutikman, Вы писали:
L>Добрый день.
L>Хочу с помощью PropertyGrid реализовать изменение и сохранение настроек программы. Но параметры заранее не известны и будут иметь след структуру:
C#. Разработка компонентов в MS Visual Studio 2005/2008
6.7. Виртуальные свойства
В предыдущем разделе мы удаляли свойство из списка свойств. Было бы логично разобраться с тем, как добавлять свойства в этот список, т. е. создавать дополнительные свойства компонента, которые существуют только в режиме разработки. Посмотрите, например, на свойства группы Design (рис. 6.8). Свойства GenerateMember, Locked являются виртуальными. Реально у компонента GradientLabel таких свойств нет.
Для того чтобы добавить свойство, существующее только в режиме разработки, нужно добавить его в словарь properties в методе PreFilterProperties(), а само свойство будет существовать только в классе дизайнера:
class GradientLabelDesigner : ControlDesigner
{
int virtualProp;
[DesignerSerializationVisibility(
DesignerSerializationVisibility.Hidden)]
[Description("Виртуальное свойство")]
public int VirtualProp
{
get { return virtualProp; }
set { virtualProp = value; }
}
}
Как я уже говорил, словарь properties представляет собой связь между именем свойства и его дескриптором, т. е. для добавления свойства нам потребуется дескриптор. Получить его можно двумя способами. Первый – создать дескриптор с помощью метода CreateProperty() класса TypeDescriptor:
PropertyDescriptor descr = TypeDescriptor.CreateProperty(
base.GetType(), "VirtualProp", typeof(int), new Attribute[0]);
Первый параметр передает тип класса, к которому будет добавлен метод, второй – имя метода, третий – тип и четвертый задает атрибуты. Недостаток этого способа именно в отсутствии атрибутов. Перечислять необходимые атрибуты вручную довольно затруднительно, поэтому лучше пойти другим путем и копировать атрибуты существующего свойства:
PropertyDescriptor oldDescr =
TypeDescriptor.GetProperties(this)["VirtualProp"];
Attribute [] attributes = new Attribute [descr.Attributes.Count];
descr.Attributes.CopyTo(attributes, 0);
PropertyDescriptor descr = TypeDescriptor.CreateProperty(
base.GetType(), descr, attributes);
После этого можно добавить его в свойства компонента:
properties["VirtualProp"] = descr;
Очень важно чтобы виртуальное свойство имело атрибут DesignerSerializationVisibility.Hidden (см. разд. 10.4), т. к. иначе оно попадет в свойства режима выполнения.
Полный код дизайнера, добавляющего виртуальное свойство, приведен в листинге 6.9.
Еще раз к вопросу о виртуальных свойствах я вернусь в разд. 7.18.
Рис. 6.8. Виртуальные свойства компонента
Листинг 6.9 Добавление виртуального свойства VirtualProp
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms.Design;
using System.Drawing;
using System.ComponentModel;
using System.Windows.Forms;
namespace MyControl
{
class GradientLabelDesigner : ControlDesigner
{
int virtualProp;
[DesignerSerializationVisibility(
DesignerSerializationVisibility.Hidden)]
[Description("Виртуальное свойство")]
public int VirtualProp
{
get { return virtualProp; }
set { virtualProp = value; }
}
protected override void PreFilterProperties(
IDictionary properties)
{
base.PreFilterProperties(properties);
// Берем существующее свойство
PropertyDescriptor oldDescr =
TypeDescriptor.GetProperties(this)["VirtualProp"];
// Копируем его атрибуты
Attribute[] attributes =
new Attribute[oldDescr.Attributes.Count];
oldDescr.Attributes.CopyTo(attributes, 0);
// Создаем новое свойство
PropertyDescriptor descr =
TypeDescriptor.CreateProperty(
base.GetType(), oldDescr, attributes);
// Добавляем его в свойства компонента
properties["VirtualProp"] = descr;
}
}
}
Здравствуйте, lutikman, Вы писали:
L>Не отказался бы от примера в виде исходного кода.
private string GenerateClassCode()
{
StringBuilder sb = new StringBuilder();
for (int n = 0; n < 6; n++)
{
sb.AppendFormat(@"
private string field{0} = """";
[Category(""{1}"")]
[DefaultValue("""")]
public string Prop{0}
{{
get {{ return field{0}; }}
set {{ field{0} = value; }}
}}
",
n, n < 3 ? "Category1" : "Category2");
}
return string.Format(@"
using System.ComponentModel;
public class MyType
{{
{0}
}}",
sb);
}
private Assembly CompileSourceCode(string text)
{
CompilerParameters parameters = new CompilerParameters();
parameters.ReferencedAssemblies.Add("System.dll");
parameters.GenerateInMemory = true;
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerResults results = provider.CompileAssemblyFromSource(parameters, text);
return results.CompiledAssembly;
}
public Form1()
{
InitializeComponent();
Assembly assembly = CompileSourceCode(GenerateClassCode());
Type type = assembly.GetType("MyType");
object obj = type.GetConstructor(Type.EmptyTypes).Invoke(null);
this.propertyGrid1.SelectedObject = obj;
}
Здравствуйте, lutikman, Вы писали:
L>Хочу с помощью PropertyGrid реализовать изменение и сохранение настроек программы. Но параметры заранее не известны и будут иметь след структуру:
…
L>Помогите реализовать подобное.
Understanding the TypeDescriptor: A Metadata Engine for Designtime Code