базовый класс не всегда вызывается при создании экземпляра пользовательского элемента управления WinForm - PullRequest
0 голосов
/ 06 сентября 2011

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

В основном у меня есть несколько пользовательских элементов управления с одним базовым классом, который захватывает экземпляр моего основного окна формы, поэтому пользовательский элемент управления имеет доступ к основным свойствам формы и может вызывать методы в главной форме.Вот фрагмент кода (this.frmParent является открытым членом):

    private void ucBase_Load( object sender, EventArgs e )
    {
        // Establish the link to the main form.
        this.frmParent = FindForm() as frmMain;
    }

Тогда каждый пользовательский элемент управления разделяет этот базовый класс:

public partial class ucLiberty : ucBase

Затем в основной форме явызвать пользовательский элемент управления следующим образом:

                ucLiberty Liberty = new ucLiberty();
                IQDevicePath = Liberty.GetIQDrivePath();

По какой-то причине, когда я создаю экземпляр пользовательского элемента управления (в данном случае он находится в основной форме), переменная frmParent в базовом классе может быть заполнена или не заполненас ненулевым значением.

Я заметил, что событие загрузки в пользовательском элементе управления не запускается.Я нашел метод CreateControl (), который должен форсировать создание элемента управления, и затем мое событие загрузки начало срабатывать, однако, когда я проследил выполнение в отладчике и попал в базовый класс, где он пытался заполнить frmParent,FindForm () не всегда возвращает ненулевое значение.

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

Мой обходной путь - отслеживать, в каком пользовательском элементе управления происходит сбой FindForm (), и в событии загрузки этого пользовательского элемента управления присваивать значение с помощью вызова конструктора главной формы, что-токак это:

this.frmParent = new frmMain();

Однако мне все еще нужно вызывать CreateControl () для запуска события load, и мне не нравится идея требовать, чтобы будущие сопровождающие имели явные знанияразличных поведенческих императивов.Другими словами, я бы хотел, чтобы все мои пользовательские элементы управления работали одинаково для простоты обслуживания.

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

У кого-нибудь есть идеи по поводу решения этих проблем?Благодарю.

Ответы [ 2 ]

2 голосов
/ 06 сентября 2011

Вы совершаете довольно серьезный грех ООП, сообщая пользователю о форме, в которой он находится. предполагается, что является независимым классом, который не заботится о своем контейнере. Вы используете события, чтобы позволить контейнеру знать обо всем, что произошло в вашем классе, и может заинтересовать контейнер. Принцип дизайнаэто сопровождается буквой любым из стандартных элементов управления в Winforms.Например, TextBox никогда не заботится о том, на какую форму он помещен.

Это теория, практика не всегда так чиста.Проблема, с которой вы столкнулись, состоит в том, что метод OnLoad (он же событие Load) запускается по другой причине.Он запускается, когда создается собственный дескриптор Windows.Что обычно происходит, когда создается окно формы, запускаемое вызовом метода Show ().Это после метода IntializeComponent () формы.

Если у вас есть какой-либо код в конструкторе вашего пользовательского элемента управления, который требует, чтобы свойство Handle имело значение, тогда Winforms обязуется и создает дескриптор Windows дляваш контроль и запускает событие Load.Слишком скоро, прежде чем у метода InitializeComponent () появилась возможность вызвать метод Controls.Add ().Свойство Parent еще не ссылается на форму.Kaboom на FindForm ().

Это легко диагностировать с помощью отладчика.Установите точку останова на методе OnLoad пользовательского элемента управления.Трассировка стека приведет вас прямо к утверждению, которое инициировало создание дескриптора.

0 голосов
/ 06 сентября 2011

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

public class frmMain : Form
{
     private static frmMain s_Singleton;

     public static frmMain Singleton
     {
          get
          {
              if (s_Singleton == null) s_Singleton = new frmMain();
              return s_Singleton;
          }

     }
}

Таким образом, вместо того, чтобы когда-либо вызывать конструктор напрямую, вызовите frmMain.Singleton для ссылки (даже в (особенно в!) Файле Program.cs, где форма, скорее всего, изначально построена). Кроме того, у вас есть глобально доступная ссылка на вашу основную форму, доступную по телефону frmMain.Singleton в ваших пользовательских элементах управления

Что касается причины, по которой ваш ucBase_Load не загружается, мое необразованное предположение состоит в том, что вы также обрабатываете событие в конкретном пользовательском элементе управления и что он каким-то образом останавливает запуск базового обработчика. Если это так, добавьте base.OnLoad() в обработчик событий вашего конкретного пользовательского элемента управления.

А что касается того, почему FindForm не работает, это может быть вызвано тем, что метод вызывается до завершения конструктора пользовательского элемента управления. Это кажется маловероятным, но трудно сказать наверняка, не увидев ваш код. Это может быть связано с тем, что родительский элемент управления и т. Д. Настроен в конструкторе. Но так как вы обрабатываете это в событии Load, это кажется маловероятным. Вы можете проверить эту теорию, переместив логику в событие OnParentChanged.

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

...