Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / WinForms, .Net Framework Новый топик    Ответить
 Проперти грид -> как добавить свои настройки а не контролов.  [new]
Чиграборти
Member

Откуда:
Сообщений: 143
Люди, в стандартный набор контролов входит и PropertyGrid, его хочу использовать, для
создания формы настройки программы. Как мне программно добавить в него свойства и значения,
чтобы пользователь мог или вписывать значения или выбирать из списка(combo).?
Коммерческие контролы не подходят.
8 июл 08, 21:34    [5905419]     Ответить | Цитировать Сообщить модератору
 Re: Проперти грид -> как добавить свои настройки а не контролов.  [new]
Dr_Wolf
Member

Откуда: Муром
Сообщений: 352
http://rsdn.ru/article/dotnet/PropertyGridFAQ.xml
8 июл 08, 21:58    [5905510]     Ответить | Цитировать Сообщить модератору
 Re: Проперти грид -> как добавить свои настройки а не контролов.  [new]
IApple
Member

Откуда:
Сообщений: 320
Может пригодится...
у меня после доделок (из нескольких чужих примеров) под свои нужды (мне интересна была многоязыковая поддержка интерфейса самой программы в т.ч. подсказок самого PropertyGrid), вышел класс Config, который через свои поля и свойства реализует настройки программы. В первом куске кода описание сопутствующих классов и постоянной части реализации класса:

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Xml.Serialization;
using System.IO;
using System.ComponentModel;

namespace KOMUNA
{
    public enum ChangeAction
    {
        NoAction = 0,
        Refresh = 1,
        Restart = 2
    }

    // Размечать свойства будем атрибутом ChangeProperty()
    [AttributeUsage(AttributeTargets.Property)]
    public class ChangePropertyAttribute : System.Attribute 
    {
        private ChangeAction _action;
        public ChangePropertyAttribute( ChangeAction action)
        {
            _action = action;
        }
        public virtual ChangeAction Action
        {
            get { return _action; }
        }
    }


    public class PropDispNameWrapper : ICustomTypeDescriptor
    {
        // Оборачиваемый объект.
        private object _obj;
        // Коллекция, хранящая обертки над описаниями свойств.
        PropertyDescriptorCollection _propsCollection;

        // Позволяет получить обернутый объект.
        public object Unwrap { get { return _obj; } }

        public PropDispNameWrapper(object obj)
        {
            // Запоминаем оборачиваемый объект.
            _obj = obj;
            // Создаем новую (пустую) коллекцию описаний свойств, 
            // в которую поместим обертки над реальными описаниями.
            _propsCollection = new PropertyDescriptorCollection(null);
            PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(obj, true);
            // Перебираем описания свойств, создаем для каждого 
            // из них обертку и помещаем ее в коллекцию.
            foreach (PropertyDescriptor pd in pdc)
                _propsCollection.Add(new MyPropDesc(pd));
        }

        /////////////////////////////////////////////////////////
        /// ICustomTypeDescriptor
        ///
        AttributeCollection ICustomTypeDescriptor.GetAttributes()
        {
            return new AttributeCollection(null);
        }

        string ICustomTypeDescriptor.GetClassName()
        {
            return null;
        }

        string ICustomTypeDescriptor.GetComponentName()
        {
            return null;
        }

        TypeConverter ICustomTypeDescriptor.GetConverter()
        {
            return null;
        }

        EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
        {
            return null;
        }


        PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
        {
            return null;
        }

        object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
        {
            return null;
        }

        EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
        {
            return new EventDescriptorCollection(null);
        }

        EventDescriptorCollection ICustomTypeDescriptor.GetEvents
            (Attribute[] attributes)
        {
            return new EventDescriptorCollection(null);
        }

        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
        {
            return _propsCollection;
        }

        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(
            Attribute[] attributes)
        {
            return _propsCollection;
        }

        object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
        {
            return this;
        }
    }

    public class MyPropDesc : PropertyDescriptor
    {
        PropertyDescriptor _PropDesc;

        public MyPropDesc(PropertyDescriptor PropDesc)
            : base(PropDesc)
        {
            _PropDesc = PropDesc;
        }
        public override string Description
        {
            get
            {
                string s = Properties.Resources.ResourceManager.GetString(_PropDesc.Description);
                if (s == null)    // не найден такой ресурс
                    return _PropDesc.Description;
                else return s;
            }
        }
        public override string Category 
        {
            get 
            {
                string s = Properties.Resources.ResourceManager.GetString(_PropDesc.Category);
                if (s == null)    // не найден такой ресурс
                    return _PropDesc.Category;
                else return s;
            } 
        }

        // Этот атрибут возвращает название свойства для отображения в propertyGrid (либо идентификатор строкового ресурса в Properties.Resources программы - для поддержки многоязычного интерфейса в самом propertyGrid)
        public override string DisplayName
        {
            get
            {
                // Пытаемся получить атрибут DisplayNameAttribute.
                // В случае неудачи будет возвращен null.
                DisplayNameAttribute mna =
                    _PropDesc.Attributes[typeof(DisplayNameAttribute)] as DisplayNameAttribute;
                if (mna != null)
                {
                    // Если имеется атрибут DisplayNameAttribute,
                    // то пробуем найти соответствующий языковой ресурс
                    string s;
                    s = Properties.Resources.ResourceManager.GetString(mna.ToString());
                    if (s == null)
                        return mna.ToString(); // значит это не идентификатор ресурса, а само название для свойства
                    else return s;
                }
                // Если атрибут DisplayNameAttribute не задан, возвращаем оригинальное имя свойства.
                return _PropDesc.Name;
            }
        }

        public override Type ComponentType
        {
            get
            {
                return _PropDesc.ComponentType;
            }
        }

        public override bool IsReadOnly
        {
            get
            {
                return false;
            }
        }

        public override Type PropertyType
        {
            get
            {
                return _PropDesc.PropertyType;
            }
        }

        public override bool CanResetValue(object component)
        {
            return _PropDesc.CanResetValue(((PropDispNameWrapper)component).Unwrap);
        }

        public override object GetValue(object component)
        {
            return _PropDesc.GetValue(((PropDispNameWrapper)component).Unwrap);
        }

        public override void ResetValue(object component)
        {
            _PropDesc.ResetValue(((PropDispNameWrapper)component).Unwrap);
        }

        public override void SetValue(object component, object value)
        {
            _PropDesc.SetValue(((PropDispNameWrapper)component).Unwrap, value);
        }

        public override bool ShouldSerializeValue(object component)
        {
            return _PropDesc.ShouldSerializeValue(
                ((PropDispNameWrapper)component).Unwrap);
        }
    }

    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
    [Serializable]
    public class DisplayNameAttribute : Attribute
    {
        string _sText;
        public DisplayNameAttribute(string Text)
            : base()
        {
            _sText = Text;
        }
        public override string ToString()
        {
            return _sText;
        }
    }

    public partial class Config
    {
        private static object lockFlag = new object();
        private static Config instance;
        
        [XmlIgnore]
        public static Config Instance
        {
            get
            {
                lock (lockFlag)
                {
                    if (instance == null)
                    {
                        try
                        {
                            // Пытаемся загрузить файл с диска и десериализовать его
                            using (FileStream fs = new FileStream(GetFName(), FileMode.Open))
                            {
                                System.Xml.Serialization.XmlSerializer xs =
                                    new System.Xml.Serialization.XmlSerializer(typeof(Config));
                                instance = (Config)xs.Deserialize(fs);
                            }
                        }
                        catch 
                        {   //Если не удалось десериализовать то просто создаем новый экземпляр
                            instance = new Config();
                        }
                    }
                }
                return instance;
            }
        }

        public static void Reload()
        {   // перезагрузить наново настройки з файла
            instance = null;
        }
        public static string GetFName()
        {   // должен вернуть Path + FileName конфигурационного файла
            return Application.StartupPath + "\\config.xml";
        }
        public void Save()
        {
            using (FileStream fs = new FileStream(GetFName(), FileMode.Create))
            {
                System.Xml.Serialization.XmlSerializer xs =
                    new System.Xml.Serialization.XmlSerializer(typeof(Config));
                xs.Serialize(fs, instance);
            }
        }
        public static Config GetClone()
        {   
            return (Config)Instance.MemberwiseClone();
        }
        public static void NewConfig(Config cfg)
        {
            instance = cfg;
        }
    }
}

Во втором куске кода, частичное описание класса Config с полями и свойствами именно настроек программы, которые пишутся в xml-файл либо показываются для редактирования в PropertyGrid:
строкf подключения к серверу БД - просто редактируется, язык интерфейса программы - выбирается из списка, который записан в Properties.Settings.Default.LangCollection

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Xml.Serialization;
using System.Globalization;
using System.ComponentModel;
using System.Drawing;

namespace KOMUNA
{
    public partial class Config
    {
        // Тут отдельно только поля и properties конфигурации
        // поля (fields) в PropertyGrid - не будут видны
        // а properties будут, если не указан атрибут [Browsable(false)]
        
        public string MyLang = "ru";

        [XmlIgnore] // не будет записан в файл конфигураци
        // указать ID строкового ресурса из Properties.Resourses  !!!
        // иначе не будет перевода для другого языка интерфейса
        [Category("MyLangCategory")]
        [Description("MyLangDName")]
        [DisplayName("MyLangDName")]
        //[ChangeProperty(ChangeAction.Refresh)]
        [TypeConverter(typeof(MyLangTypeConverter))]
        public string XLang
        {
            get { return System.Globalization.CultureInfo.GetCultureInfo(MyLang).NativeName;}
            set { 
                MyLang = "";
                foreach (string S in Properties.Settings.Default.LangCollection)
                    if (System.Globalization.CultureInfo.GetCultureInfo(S).NativeName == value)
                    {
                        MyLang = S;
                        break;
                    }; 
            }
        }
        
        /*
        // Фонт
        private Font _MyFont;
        [Category("MyConnStrCategory")]
        [Description("MyFont")]
        [DisplayName("MyFont")]
        //[Browsable(false)]
        public Font MyFont
        {
            get { return _MyFont; }
            set { _MyFont = value; }
        }
        */

        // строка подключения к серверу
        private string _ConnStr;
        [Category("MyConnStrCategory")]
        [Description("MyConnStr")]
        [DisplayName("MyConnStr")]
        //[Browsable(false)]
        public string ConnStr
        {
            get { return _ConnStr; }
            set { _ConnStr = value; }
        }
    }
    // Конвертер для показа языка интерфейса "строкой"
    class MyLangTypeConverter : StringConverter
    {
        public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
        {
            return true;   // Будем предоставлять выбор из списка
        }
        // ... и только из списка
        public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
        {
            // false - можно вводить вручную
            // true - только выбор из списка
            return true;
        }
        public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
        {
            // А вот и список - список строк из настроек программы
            System.Collections.Specialized.StringCollection X =
                new System.Collections.Specialized.StringCollection();
            foreach (string S in Properties.Settings.Default.LangCollection)
            {
                // реально в списке хранятся сокращения для культур: "ru","uk"...
                // а для выбора будут предоставлены NativeName: "русский", "українська"...
                X.Add(System.Globalization.CultureInfo.GetCultureInfo(S).NativeName);
            }
            return new StandardValuesCollection(X);
        }
    }
}


Настройки в программе получить из статической части класса Config можно обратившись к Config.Instance:

Config.Instance.MyLang - язык интерфейса (в форме "ru","uk"...)
Config.Instance.ConnStr - строка подключения

Для установки интерфейса программы например изменяю модуль Program.cs так:

    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>

        // Глобальные для программы константы

        static public SqlConnection Conn; // этот коннект раздавать по всей программе
        static public SqlConnectionStringBuilder SCSB;

        [STAThread]
        static void Main()
        {
            string Login = "";
            string PSW = "";
            
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            try
            {
                // установить язык интерфейса
                Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(Config.Instance.MyLang);
                
                // начальная строка подключения
                SCSB = new SqlConnectionStringBuilder(Config.Instance.ConnStr);
                // спросить логин-пароль
                DialogResult R = GetPassword(ref Login, ref PSW);
                if (R == DialogResult.OK)
                {
                    SCSB.UserID = Login;
                    SCSB.Password = PSW;
                    Conn = new SqlConnection(SCSB.ConnectionString);

                    Conn.Open();       // попробовать коннект
                    Conn.Close();

                    // теперь можно создать главную форму
                    MainForm MF = new MainForm();
                    Application.Run(MF);
                }
            }
            catch (Exception e)
            {
            }
        }
    }

Для редактирования настроек отдельная форма с PropertyGrid (PG), которому при создании формы скармливается копия настроек:
PG.SelectedObject = new PropDispNameWrapper(Config.GetClone());

Запись в файл так:
                try
                {
                    Config.NewConfig((Config)((PropDispNameWrapper)PG.SelectedObject).Unwrap);
                    Config.Instance.Save();
                    // "ConfigSaveOk"
                }
                catch (Exception ex)
                {
                    // "ConfigSaveError"+ex.Message
                }

кроме того расписаны действия при изменении свойств конфигурации (у меня они ничего не делают, но могут пригодиться):

        private void PropertyValueChanged(object sender, PropertyValueChangedEventArgs e)
        {
            Type t = typeof(ChangePropertyAttribute);
            ChangePropertyAttribute attr = (ChangePropertyAttribute)e.ChangedItem.PropertyDescriptor.Attributes[t];
            ChangeAction act = ChangeAction.NoAction;
            if (attr != null)
                act = attr.Action;
            StrongAction(act);
        }

        private void StrongAction(ChangeAction action)
        {
            _action |= action;
        }

        private ChangeAction _action;
        public ChangeAction Action
        {
            get { return _action; }
        }
    }
9 июл 08, 12:58    [5908246]     Ответить | Цитировать Сообщить модератору
Все форумы / WinForms, .Net Framework Ответить