Пользовательское свойство Winforms не удается перезагрузить-отредактировано
У меня есть пользовательское свойство в моем компонентном объекте, которое является объектом, содержащим другой объект, который является общей коллекцией другого объекта, а также одним объектом. Выглядит это примерно так:
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] [Editor(typeof(ControlsEditor), typeof(UITypeEditor))] public DialogControls Controls { get; set; } = new DialogControls(); [Serializable] public class DialogControls : ControlGroup<Control> Controls { get; set; } = new ControlGroup<Control>(); Control SelectedItem { get; set; } = null; } [Serializable] public class ControlGroup<T> : IList<T>, ICollection where T:Control{ List<T> _controls; // Implement interfaces here } [Serializable] public abstract class Control { //... a couple of protected members and abstract methods }
Все классы, наследуемые от элемента управления, также сериализуемы.
Когда я ввожу список элементов управления через пользовательский редактор, все работает нормально, и свойство сохраняется в файле ресурсов, как и ожидалось. Однако, когда я загружаю конструктор для формы, содержащей компонент, я получаю ошибку
Объект типа "система".Коллекции.Универсальный.Список`1[CommonItemDialog.CommonFileDialog+Control] "не может быть преобразован в тип" системы.Коллекции.Универсальный.Список`1[CommonItemDialog.CommonFileDialog+Control]'. Строка 264, позиция 5. не может быть проанализирована.
Если я закрою Visual Studio, а затем снова открою решение, форма появится нормально, и все мои настройки свойств останутся нетронутыми. Однако если я изменяю другой модуль (даже комментарий), Эта ошибка возвращается в конструкторе, и мне приходится закрывать VS и снова открывать его, чтобы избавиться от нее.
[Редактировать]
Я обнаружил, что это происходит только тогда, когда у меня добавлен сложный объект управления - следующий код демонстрирует:
public class ControlItem : Control { public string Label { get; set; } // All virtual methods implemented } public interface IControlContainer<T> where T:Control { ControlGroup<ControlItem> Controls { get; set; } } public class ComboBox : IControlContainer<ControlItem>, Control { public ControlGroup<ControlItem> Controls { get; set; } = new ControlGroup<ControlItem>(); }
Именно тогда, когда я добавляю такой элемент управления, как ComboBox, начинаются мои проблемы.
Просто к вашему сведению-эти элементы управления становятся пользовательскими элементами управления в реализации IFileDialogCustomize. Когда я запускаю тестовую форму с добавлением этих элементов управления, она работает отлично, и ComboBox действительно правильно отображается в CommonItemDialog.
[Правка 18 Января]
Проблема, по-видимому, напрямую связана с десериализацией элементов универсальных списков, когда объект в списке является производным от универсального типа списка (т. е. список элементов управления сталкивается с проблемой десериализации объекта ComboBox).
То, что я пытаюсь сделать, трояко:
- Удаление универсального параметра из внешних классов коллекций и объявление различных типов для каждой из коллекций.
- Реализация ISerializable на всех объектах Управления. Это также включает в себя проверку наличия конструктора по умолчанию для каждого типа.
- Сериализация и десериализация универсальных списков в виде массивов, а не в виде списков
Надеюсь, одно из этих изменений решит проблему - я опубликую его в качестве ответа, если они это сделают.
Что я уже пробовал:
Я попытался сбросить DesignerSerializationVisibility на Content, и я получаю аналогичную ошибку, которую я разрешаю сам таким же образом (т. е. закрываю VS и снова открываю решение).
Ralf Meier
Я не совсем понимаю вашу проблему ... но вы можете попробовать следующее :
- пусть свойство "Controls" имеет только Геттер (сделайте из него свойство только для чтения).
- измените атрибут "DesignerSerializationVisibility" на "DesignerSerializationVisibility".Содержание"
Если это не соответствует вашей проблеме-пожалуйста, объясните свою классовую структуру, которую вы хотите иметь ...
Midi_Mick
1. Я не могу позволить собственность есть только геттер - он должен быть установлен редактора uitypeeditor я создал, чтобы установить всю конструкцию вверх.
2. Я сделал попробуйте установить атрибут DesignerSerializationVisibility.Содержание, но я получил аналогичную ошибку с теми же симптомами. Затем произошла ошибка при установке члена списка элементов управления, и он жаловался на ограничение универсального типа (не могу точно вспомнить, что он сказал). Однако сброс VS еще раз временно очистил ошибку, и тестовая программа по-прежнему работала нормально.
Ralf Meier
Хорошо ... тогда "пожалуйста, объясните свою классовую структуру, которую вы хотите иметь"
И... для чего именно вам нужен UITypeEditor в этом особом месте ? Обычно класс-объект должен работать с ExpandableObjectConverter.
Midi_Mick
Они есть в коде. Все определенные классы являются классами-членами компонента CommonFileDialog, который содержит свойство "DialogControls Controls". Каждый класс элемента управления наследует свойство uint ID, свойство State (которое является значением перечисления) и виртуальный метод AddToDialog (), поэтому элемент управления знает, как добавить себя в компонент. Как уже упоминалось, проблема возникает, когда я включаю элемент управления, содержащий контрольную группу других элементов управления - существует множество типов, которые делают это - ComboBox выше является примером.
Ralf Meier
Я имею в виду ваши последние изменения в вашем вопросе.
Когда я начал свой комментарий, я подумал, что это та часть, с которой я очень хорошо знаком. На самом деле я не могу следовать за тобой и за тем, чего ты пытаешься достичь. Может быть, вы дадите еще какую-нибудь информацию ...
Со списком свойств я согласен с вашим наблюдением. Если есть список определенного типа (List (of myClassTtype)), то для дизайнера нет проблем сериализовать его - но я никогда не пробовал его со списком неопределенного типа ...
Midi_Mick
Я создаю классы для элементов управления, которые будут созданы в CommonFileDialog, используя интерфейс IFileDialogCustomize. Таким образом, мой базовый абстрактный класс "Control" имеет 2 свойства, общие для всех элементов управления (ID и ControlState), и будет знать, как добавить себя в диалог (Я объявляю абстрактный метод AddToDialog в базовом классе управления). В зависимости от типа элемента управления он может содержать другие свойства, характерные для этого элемента управления, которые должны быть сериализованы. Один из этих элементов управления также является элементом управления "VisualGroup", который сам содержит список других элементов управления.
Эти элементы управления хранятся в списке в моем основном классе FileDialog (который наследуется от Component) и добавляются в диалоговое окно ОС непосредственно перед их отображением. У меня есть пользовательский редактор, который позволяет мне вводить этот список во время разработки, и я ожидаю, что VS designer сериализует и десериализует список по мере необходимости. Именно во время десериализации конструктором форм списка элементов управления произошла ошибка - все это прекрасно десериализуется во время выполнения.
Midi_Mick
Близко, но сигары нет. Из-за массовых изменений, внесенных сейчас, я думаю, что мог бы перенести этот вопрос на форумы C#, так как обсуждение, похоже, идет. Пожалуйста, не увольняйте меня за это - этот вопрос в его нынешнем виде стал недействительным в его нынешнем состоянии и стал бы слишком большим, чтобы продолжать его здесь.