Подтвердить что ты не робот

Как сделать свойство управления пользователем типа Collection <MyClass> редактируемым в Form Designer?

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

В основном моя цель такова:

У меня есть UserControl1, с полем типа Collection<Class1> и соответствующим свойством Collection<Class1> Prop. Вот так:

public class UserControl1 : UserControl
{
    private Collection<Class1> field = null;
    // later changed to:
    //private Collection<Class1> field = new Collection<Class1>();
    [Category("Data")]
    [DefaultValue(null)]
    [Description("asdf")]
    public Collection<Class1> prop
    {
        get { return field; }
        set { field = value; }
    }
}
// later added:
//[Serializable]
public class Class1
{
    private bool booltest; public bool Booltest { get...set...}
    private int inttest; public int Inttest { get...set...}
}

Если вы уже знаете, что я испортил: нет необходимости читать остальные. Я расскажу, что именно я сделал.

Теперь я помещаю UserControl в случайную форму и изменяю свойство Prop. Появляется общий "Редактор коллекции", такой как тот, который используется для столбцов и групп в элементе управления listview. Я могу ввести данные, как ожидалось. Однако, когда я нажимаю OK, данные уходят.

Мне потребовалось более часа, чтобы понять, что мне действительно нужно создать экземпляр моего поля: private Collection<MyClass> field = new Collection<MyClass>();. Очень хорошо, только дизайнер вошел в режим суперпроцессинга. Сообщение об ошибке каскадного кошмара, которое можно свести к: "Вы должны поставить [Serializable] перед вашим Class1". После этого я мог бы снова разместить мой UserControl1 в форме.

Но это работает только один раз. При открытии конструктора формы, где я использую UserControl1 после редактирования чего-либо, это дает мне ошибку:

Object of type 'userctltest.Class1[]' cannot be converted to type 'userctltest.Class1[]'.

Ну. В списке ошибок говорится:

Warning: ResX file Object of type 'userctltest.Class1[]' cannot be converted to type 'userctltest.Class1[]'. Line 134, position 5. cannot be parsed.

Дизайнер пытается получить данные свойства из файла resx. Удаление файла resx "решает" это ровно один раз.

Теперь форму можно снова отобразить с помощью UserControl1. Свойство Collection доступно для редактирования, и оно сохраняется. Это действительно работает. Однажды. Всякий раз, когда я что-то меняю, а затем пытаюсь снова открыть конструктор форм, вышеуказанная ошибка возникает снова. Я могу удалить файл resx, но это, конечно же, также удалит мои данные.

Релевантные ресурсы, которые помогли мне до сих пор (среди тонны не очень полезных результатов поиска):

http://www.codeproject.com/Answers/190675/Usercontrol-with-custom-class-property#answer1
http://www.codeproject.com/KB/cs/propertyeditor.aspx
http://www.csharpfriends.com/Articles/getArticle.aspx?articleID=94
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.iserializable.aspx

(Я также попытался реализовать ISerializable и переопределить GetObjectData с помощью

{ info.AddValue("testbool", testbool); info.AddValue("testint", testint); }

тоже не помогло (я также попробовал имена свойств вместо имен полей))

Извините за то, что написал это как плохой роман ужасов кстати.

4b9b3361

Ответ 1

То, что вы хотите, это поддержка времени разработки с сериализацией CodeDom. Вам не нужны SerializableAttribute или ISerializable, для двоичной сериализации. Поскольку вы хотите сериализовать коллекцию, вы должны сказать разработчику сериализовать ее как таковую. Это делается с помощью атрибута DesignerSerializationVisibiliby - значение Content указывает конструктору сериализовать содержимое свойств, а не собственное свойство. Содержание свойства должно быть, конечно, сериализуемым кодом CodeDom, который по умолчанию имеет простые классы с простыми свойствами.

Итак, если вы измените свой класс UserControl1 следующим образом:

public class UserControl1 : UserControl
{
    private Collection<Class1> field = new Collection<Class1>();

    [Category("Data")]
    [Description("asdf")]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public Collection<Class1> prop
    {
        get { return field; }
    }
}

... он должен сделать трюк. Ох и свойства коллекции обычно не могут быть записаны, хотя это необязательно. Но serializer ожидает, что свойство collection будет инициализировано, поэтому вам нужно было добавить инициализацию для этого поля. Другое примечание: если вы не хотите, чтобы ваше свойство выделено жирным шрифтом в редакторе свойств, вы можете указать более сложное "значение по умолчанию" с помощью специального метода ShouldSerializePropertyName, который может быть даже закрытым. Например:

private bool ShouldSerializeprop() 
{
    return (field.Count > 0);
}

Теперь ваше свойство будет только полужирным, если оно не пустое. Но я отвлекся, это не вопрос:)

Ответ 2

Идеальный пример:

public partial class SCon : UserControl
    {
        public SCon()
        {
            InitializeComponent();
            if (Persoanas == null)
            {
                Persoanas = new List<Persoana>();
            }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public List<Persoan> Persoanas { get; set; }

    }

    [Serializable]
    public class Persoan   
    {
        public int Id { get; set; }
        public String Name { get; set; }
    }

Ответ 3

Просто измените Collection<> на List<>