Багоспасаемая держава
— За что Нео признали в Матрице экстремистом?
— За антисмитизм!
Багоспасаемая держава
— За что Нео признали в Матрице экстремистом?
— За антисмитизм!
Если нам нужно найти контрол на форме, зная его имя, то все решается довольно просто — у массива контролов Controls
есть метод Find
, который найдет нам что нужно, если указать правильное имя контрола:
private Control FindControl(string ControlName, Form form) { Control ctrl = null; Control[] buf = form.Controls.Find(ControlName, true); if (buf.Length == 0) return null; if (buf.Length > 1) return null; ctrl = buf[0]; return ctrl; }
Вот тут уже сложнее, особенно с переключателями. Они обычно сидят на форме в контейнерах, например в GroupBox'ах
, и функция Find
тут не поможет. Необходим другой подход, если мы хотим получить список контролов определенного типа. А именно — надо сделать рекурсивную функцию поиска. Кто боится рекурсии и связанных с ней переполнений, скажу, что ничего страшного нет.
Мне удалось уронить студию на 5 000 однотипных компонентов, а подобное число компонентов вряд ли может быть в реальности, только если вы не радиокнопочный маньяк 🙂
Функция такая вот:
private ListFindAllRadiobuttons(Control.ControlCollection collection) { List result = new List (); foreach (Control ctrl in collection) { if (ctrl.HasChildren) { result.AddRange(this.FindAllRadiobuttons(ctrl.Controls)); } if (ctrl is RadioButton) { result.Add((RadioButton)ctrl); } } return result; }
Т.е. если мы просто наткнулись на переключатель, при переборе контролов из массива Controls, то добавляем переключатель в массив, если же, мы наткнулись на контрол-контейнер (ctrl.HasChildren == true
), то вызываем функцию перебора массива уже для массива Controls
контейнера.
В прошлой части Копия я рассказывал, как с помощью инструментов из пространства имен System.Reflection
, можно сохранить свойства объекта, например, в таблицу DataSet
, или наоборот, загрузить из DataSet
данные в свойства соответствующего объекта. Таким образом, решалась проблема автоматизации работы с конфигурационными файлами.
Есть способ еще более уменьшить количество кода, воспользовавшись стандартным механизмом .NET Framework — сериализацией. Сериализация, это, по рабоче-крестьянски говоря, именно что сохранение состояния объекта (он же пафосно называется «экземпляром класса») в некий передаваемый формат. Доскональное объяснение, что это такое, в статью не влезет, потому оставим.
Итак, переходим к сериализации.
В .NET Framework сам себя класс сериализовать не может, точнее, сериализовать-то может, а вот десериализовать — нифига. Класс и его экземпляр, получается, как Штирлиц с раненой радисткой Кэт, передать могут, а обратно нет, без дружественной помощи.
Поэтому, придется изобретать выход, в котором классов будет больше, а кода меньше, чем в предыдущем случае
Выход в том, чтобы создать класс, непосредственно хранящий конфигурацию, и класс-менеджер, который возьмет на себя работу над сериализацией, десериализацией и другим, например, назначением значений по умолчанию.
Итак, создадим класс-хранилище, вот такой вот, например:
[Serializable] public class AppSettings { public string DataUrl { get; set; } public FormatType DataFormat { get; set; } public string IPColumn { get; set; } public string FieldSeparator { get; set; } public string FlagColumn { get; set; } public string TrueValue { get; set; } public string FalseValue { get; set; } public bool LoadUpdate { get; set; } public AppSettings() { } }
Если нужно, чтобы класс сериализовался, то перед описанием класса нужно обязательно установить атрибут «сериализуемый»:
[Serializable]
Далее нам надо выбрать сериализатор, т.е. набор методов, который будет данные нашего класса во что-нибудь преобразовывать, или наоборот, восстанавливать, загружая ранее сохраненные значения.
Ну, раз уж в прошлый раз, мы выбирали XML, то и сейчас я буду сериализовывать класс в XML
Сериализатор XML в .NET пропускает все приватные поля и свойства класса. На мой взгляд, это больше хорошо, чем плохо, если сохранять класс, хранящий набор параметров конфигурации — приватные все равно не нужны.
Если какое-то публичное свойство не надо сериализировать, т.е. в нашем случае, сохранять в конфиг, то такому свойству надо установить атрибут [XmlIgnore]
, для публичных полей устанавливается атрибут [NonSerialized]
.
Например:
[XmlIgnore]
public string DataUrl { get; set; }
Последняя особенность сериализации в XML — сериализируемому классу необходим конструктор без параметров, причем, практически выявлено, в этом конструкторе лучше вообще ничего не делать, особенно того, что может привести к ошибкам времени выполнения. Иначе получите гадскую невыявляемую ошибку, поскольку в отладке у вас будет всякая фигня, кроме того, чего нужно.
Я так понимаю, конструктор без параметров вызывается во время XML-сериализации, и наверняка, в нем что-то можно и нужно делать, но пока я не нашел, как и где это подробно расписать.
Само дерево жужжать не может
Значит, кто-то тут жужжит
(Вини-Пух)
Это самая гадская особенность сериализации в .NET, а именно, если в прошлом случае могли параметры конфига, и функции для их сохранения-загрузки объединить в один класс, то в подходе с использованием сериализации не можем:
this = (Data)readerRr.Deserialize(fileRr);
this - переменная только для чтения, по крайней мере до .NET 4.0 включительно.
И такой подход считается «плохим дизайном», хотя на мой нескромный взгляд, плохой дизайн — это разносить части одного и того же по разным классам.
Но раз уж надо, значит надо. Делаем класс-менеджер:
Далее такой условный класс-менеджер с возможностью сохранения и загрузки:
Читать далее
Киберфорум
Сериализация в XML. XmlSerializer
Навел на мысль steinkrauz@ljr
Офигенная эмо-панк группа из моего города.
Тащемта, были даже на дребедне нашего города, было холодно и неприятно (от погоды), но вообще парни пиздатые. Особенно вокалист XD
Но они, как и все нормальные люди, уезжают. Жалко, но придется.
Прямая ссылка: кликать сюда
Я, как всегда немного опаздываю, потому что у меня график в интернетах абсолютно не совпадает с планетой 🙂