Пользовательский элемент управления не инициализирован в автоматически сгенерированном коде - PullRequest
12 голосов
/ 16 апреля 2011

Это случалось много раз прежде, но я так и не удосужился понять, почему, и теперь я устал от этого:

Например, я извлекаю класс из RichTextBox или Panel, я перестраиваю свой проект, чтобы добавить класс в панель инструментов дизайнера VS, а затем перетаскиваю пользовательский элемент управления в форму. Все отлично работает, и я могу запустить свой проект ...

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

Другими словами, следующая строка удаляется, скажем, из Form1.Designer.cs:

this.customRichTextBox1=new CustomRichTextBox();

Никакая другая строка не удаляется из выделенного кода, поэтому атрибуты пользовательского элемента управления по-прежнему установлены, хотя переменная остается неинициализированной.

Мое решение всегда состояло в том, чтобы вручную инициализировать мой пользовательский элемент управления в коде разработчика, но дизайнер в конечном итоге удаляет его снова.

Я считаю, что этого не происходит, когда я создаю Custom UserControl через конструктор (но я не совсем уверен в этом). Это происходит только тогда, когда я определяю что-то вроде следующего вручную:

class CustomRichTextBox:RichTextBox{}

Это так раздражает. Что я делаю не так?


По просьбе @Cody, здесь приведены шаги по воспроизведению проблемы. Я использую VS2010, но у меня эта проблема с 2005 года, я думаю.

Шаг 1. Создайте новое приложение Windows Forms, любой Framework

Шаг 2. Добавьте следующий класс ниже основного класса Form: (Бывает, что этот элемент управления вызывает у меня эту проблему в этот раз.)

class CustomRichTextBox : RichTextBox
{
    Timer tt = new Timer();

    internal CustomRichTextBox()
    {
        tt.Tick += new EventHandler(tt_Tick);
        tt.Interval = 200;
    }


    protected override void OnTextChanged(EventArgs e)
    {
        tt.Stop();
        tt.Start();
    }

    void tt_Tick(object sender, EventArgs e)
    {
        System.Diagnostics.Trace.WriteLine("Hello world!");
    }
}

Шаг 3. Нажмите F6, чтобы восстановить.

Шаг 4. Добавьте элемент управления CustomRichTextBox в форму, перетаскивая его из панели инструментов.

Шаг 5. При желании вы можете нажать F5, чтобы протестировать приложение, но оно должно работать. Закройте работающее приложение.

Шаг 6. Нажмите F6, чтобы перестроить, и на этом этапе конструктор должен аварийно завершить работу со следующим сообщением: «Переменная 'customRichTextBox1' либо необъявлена, либо никогда не была назначена». (В одном случае вся VS полностью рухнула, но ошибка обычно содержится в конструкторе.)

Шаг 7. Чтобы исправить проблему, перейдите к выделенному коду и инициализируйте переменную, но при следующем перестроении строка инициализации исчезнет.

Ответы [ 4 ]

14 голосов
/ 16 апреля 2011

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

Проблема возникает при использовании «внутреннего» ключевого слова с конструктором элемента управления.Изменение этого параметра на «общедоступное» устраняет проблему.Причиной такого поведения может быть то, что собственные классы дизайнера не могут видеть конструктор, потому что они не находятся в пространстве имен моего класса, если он не помечен как открытый.Все это имеет смысл, и теперь я буду использовать ключевое слово public.

Класс не обязательно должен находиться в отдельном файле или быть первым объявленным классом в файле, как предлагали другие ответы.

Следующий класс хорошо работает, потому что ключевое слово конструктора было изменено на public.

class CustomRichTextBox : RichTextBox
{
    Timer tt = new Timer();

    public CustomRichTextBox()
    {
        tt.Tick += new EventHandler(tt_Tick);
        tt.Interval = 200;
    }


    protected override void OnTextChanged(EventArgs e)
    {
        tt.Stop();
        tt.Start();
    }

    void tt_Tick(object sender, EventArgs e)
    {
        System.Diagnostics.Trace.WriteLine("Hello world!");
    }
}
0 голосов
/ 14 марта 2015

У меня была похожая проблема, которую мне помог решитьУ меня есть CustomControl, который расширяет ComboBox, этот класс содержал внутренний закрытый класс YearItem.Я попытался выделить только код, необходимый для понимания проблемы и решения.

public class YearsCbo : ComboBox //Inherits ComboBox
{
    public YearsCbo() { 
        fill();
    }
    private void fill() { // <<<=== THIS METHOD ADDED ITEMS TO THE COMBOBOX
        for(int idx = 0; idx < 25; idx++) {
            this.Items.Add(new YearItem());
        }
    }
    // Other code not shown
    private class YearItem {} // <<<=== The VS designer can't access this class and yet 
        // it generated code to try to do so.  That code then fails to compile.
        // The compiler error rightfully says it is unable to access 
        // the private class YearItem
}

Я мог перетащить этот элемент управления YearsCbo в форму, и он работал правильно, нопосле того, как я вернулся и отредактировал форму, конструктор VS сгенерировал код, который не будет компилироваться.Оскорбительный код примерно такой:

Dim YearItem1 As my.ns.YearsCbo.YearItem = New my.ns.YearsCbo.YearItem()
Dim YearItem2 As my.ns.YearsCbo.YearItem = New my.ns.YearsCbo.YearItem()
// This was repeated 25 times because in my constructor I created 25 of these
Me.YearsCbo1.Items.AddRange(New Object() {YearItem1, 2, 3, ..., YearItem25 });

Обратите внимание, что дизайнер сгенерировал код, который пытался получить доступ к закрытому классу.Этого не нужно было делать, но по какой-то причине это было сделано.

Через метод проб и ошибок, и этот пост: Как узнать, выполняется ли код .NET дизайнером Visual Studio придумал решение:

Я добавил свойство, чтобы сказать, работаю ли я в конструкторе.

public bool HostedDesignMode
{
    get
    {
        if (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime)
            return true;
        else
            return false;
    }
}

Я также изменил конструктор, чтобы он не вызывал fill ()поэтому, когда дизайнер работает, в ComboBox нет элементов, поэтому дизайнер не чувствует необходимости создавать эти элементы вручную.

«Фиксированный» код показан ниже:

public class YearsCbo : ComboBox //Inherits ComboBox
{
    public YearsCbo() { 
        if ( ! HostedDesignMode ) {
            fill();
        }
    }
    private class YearItem {} // <<<=== Now the VS Designer does not try to access this
}

Этот код был написан с использованием VS2012 Premium на ОС Win7x64 (на случай, если это имеет значение).

0 голосов
/ 16 апреля 2011

Вы пытались поместить контрольный код в отдельный файл? У меня были проблемы даже с конструктором форм в прошлом, когда код конструктора не был первым классом в файле.

0 голосов
/ 16 апреля 2011

Ваша сборка настроена на Debug или это Release?Я предполагаю, что это релиз, так как я думаю, что компилятор оптимизирует код и удаляет строку, сгенерированную дизайнером.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...