Пользовательские свойства, определенные в базовой форме, теряют свое состояние в унаследованной форме при перестроении.

У меня возникли проблемы со свойствами базовой формы, не поддерживающими состояние в унаследованной форме.

Окружающая среда:

  • Пакет обновления 1 для Visual Studio 2010 Ultimate: версия 10.0.40219.1 SP1Rel
  • .Net Framework: версия 4.0.30319 SP1Rel
  • Windows 7 Ultimate

Ниже приведен исходный код и шаги для воспроизведения:

using System;
using System.ComponentModel;
using System.Windows.Forms;

namespace Test
{
    public partial class BaseForm : Form
    {
        [DefaultValueAttribute(true)]
        public bool ControlVisible
        {
            get
            {
                return this.checkBox1.Visible;
            }
            set
            {
                this.checkBox1.Visible = value;
            }
        }

        [DefaultValueAttribute(false)]
        public bool ControlChecked
        {
            get
            {
                return this.checkBox1.Checked;
            }
            set
            {
                this.checkBox1.Checked = value;
            }
        }

        public BaseForm()
        {
            InitializeComponent();
        }
    }
}

В приведенном выше примере свойства по умолчанию совпадают с [DefaultValueAttribute], т. е. в InitializeComponent() для checkBox1.Visible установлено значение true, а для checkBox1.Checked — false. Это настройки по умолчанию для элемента управления при перетаскивании на форму.

Затем я создал следующую унаследованную форму:

using System;
using System.ComponentModel;
using System.Windows.Forms;

namespace Test
{
    public partial class Form1 : BaseForm
    {
        public Form1()
        {
            InitializeComponent();
        }
    }
}

Проблема и действия по воспроизведению:

  1. Когда я открываю Form1 в конструкторе, свойства находятся в следующем состоянии.

    Состояние: ControlChecked = False — ControlVisible = True (жирный шрифт)

    Для параметра ControlVisible задано значение True, как и ожидалось, однако оно выделено полужирным шрифтом. [DefaultValueAttribute] имеет значение true в базовой форме, поэтому я ожидал, что это свойство не будет выделено полужирным шрифтом.

  2. Теперь я изменяю ControlVisible на False в дизайнере. Жирный выключается.

    Состояние: ControlChecked = False — ControlVisible = False

  3. Теперь я перестраиваю проект, и код в Form1 регенерируется. Свойство ControlVisible возвращается к значению True, выделенному полужирным шрифтом.

    Состояние: ControlChecked = False — ControlVisible = True (жирный шрифт)

  4. Теперь я изменяю ControlChecked с False на True, и он становится жирным, как и ожидалось.

    Состояние: ControlChecked = True (жирный шрифт) — ControlVisible = True (жирный шрифт)

  5. Пересобираю проект и никаких изменений.

    Состояние: ControlChecked = True (жирный шрифт) — ControlVisible = True (жирный шрифт)

  6. Теперь я изменяю свойство ControlVisible с True на False и снова перестраиваю проект. Для параметра ControlVisible снова выбрано значение True, выделенное полужирным шрифтом.

    Состояние: ControlChecked = True (жирный шрифт) — ControlVisible = True (жирный шрифт)

ControlChecked работает должным образом. ControlVisible продолжает возвращаться к True, когда для него задано значение false и полужирный шрифт перевернут. Мне кажется, что каким-то образом [DefaultAttributeValue] true в базовой форме не распознается.

Обновление: исправлено, чтобы исправить ошибку и более точно изолировать проблему.

Обновление: если я устанавливаю checkBox1.Visible = false в конструкторе BaseForm, то все работает как положено. Таким образом, в итоге получается, что проблема заключается в том, чтобы DefaultValueAttribute true распознавался в пользовательском свойстве в унаследованной форме.


person Elan    schedule 29.07.2011    source источник


Ответы (2)


Является ли ваш checkBox1 закрытым в базовом классе? Если это не так, то должно быть, потому что дизайнер будет сериализовать оба сеттера (один для checkBox1.Visible, а другой для ControlVisible), и только порядок сериализации будет определять конечное состояние, что плохо.

Кроме того, посмотрите на автоматически сгенерированный метод InitializeControls в файле Form1.designer.cs, устанавливает ли он явным образом значения по умолчанию для пользовательских свойств?

Наконец, попробуйте использовать ShouldSerialze и Reset и посмотрите, получится ли у вас другое поведение.

Изменить

Я воссоздал проблему локально и подключил один экземпляр VS для отладки другого. В первый раз, когда свойство ControlVisible было оценено VS, оно вернуло false, потому что checkBox1.Visible (источник получения) было false. Когда фактический элемент управления флажком был создан и показан, а окно свойств было прокручено для отображения ControlVisible, его значение было снова оценено и возвращено true, что является значением по умолчанию, однако кажется, что VS внутренне уже пометил это было изменено, так как его начальное значение отличалось от значения по умолчанию. Это может быть ошибка в VS.

Я создал простую демонстрацию эффекта:

    public BaseForm()
    {
        InitializeComponent();
        _testValue = false;
    }

    private bool _testValue;

    [DefaultValue(true)]
    public bool TestProperty
    {
        get { return _testValue; }
        set { _testValue = value; }
    }

    protected override void OnVisibleChanged(EventArgs e)
    {            
        _testValue = true;
        base.OnVisibleChanged(e);
    }
}

При наследовании вышеуказанного BaseForm TestPropery ведет себя точно так же, как ControlVisible в вашем примере, поэтому я думаю, что это ошибка в VS.

Решение вашей проблемы состоит в том, чтобы использовать простое логическое поле поддержки в качестве помощника, потому что checkBox1.Visible ненадежен:

    public BaseForm()
    {
        InitializeComponent();
        checkBox1.Visible = _controlVisible = true;
    }

    private bool _controlVisible;

    [DefaultValue(true)]
    public bool ControlVisible
    {
        get { return _controlVisible; }
        set { _controlVisible = checkBox1.Visible = value; }
    }
person Boris B.    schedule 29.07.2011
comment
checkBox1 является закрытым в базовом классе. Form1.designer.cs явно задает ControlVisible, когда для него задано значение true, что является обратным. Это свойство по умолчанию, и оно не устанавливает его, если оно равно false. Я попробовал ShouldSerialize и Reset, и это не имело никакого значения. Унаследованная форма имеет обратное значение по умолчанию для пользовательского свойства ControlVisible. Каким-то образом он не распознает параметр DefaultAttribute в базовом классе, а также игнорирует метод ShouldSerialize/Reset. - person Elan; 29.07.2011
comment
Странно, я сделал локальную демку, и она работает так, как вы описали. Когда поле private bool является источником для ControlVisible, оно работает, как и ожидалось, но когда источником является checkBox1.Visible, оно не работает. - person Boris B.; 29.07.2011
comment
Когда я устанавливаю ControlVisible = false и изменяю [DefaultAttribute (false)] в свойстве. Затем унаследованная форма также работает должным образом. Похоже, что [DefaultAttribute(true)] не принимается. - person Elan; 29.07.2011
comment
Я провел ваш тест на частном логическом поле в качестве источника, и он работает и для меня, как и ожидалось. Хотя это неудобно, это приводит к решению зеркально отображать видимое состояние базового элемента управления (то же самое происходит с элементом управления Panel) в частном логическом поле. Было бы неплохо решить эту проблему, не отражая видимое состояние элемента управления. - person Elan; 29.07.2011

Ваше свойство ControlVisible всегда получает значение false:

    [DefaultValueAttribute(true)]
    public bool ControlVisible
    {
        get
        {
            return this.checkBox1.Visible;
        }
        set
        {
            this.checkBox1.Visible = false;
        }
    }

Ваш метод set должен быть:

    this.checkBox1.Visible = value;
person Paul    schedule 29.07.2011
comment
Действительно очень острый! Вау, это было неловко. Я исправил код, и это устранило пару аномалий — осталась одна проблема. - person Elan; 29.07.2011