Наследование обработчиков событий в C # - PullRequest
12 голосов
/ 18 сентября 2008

Я как бы загнал себя в угол здесь.

У меня есть серия UserControls, которые наследуются от родителя, которые содержат несколько методов и событий для упрощения вещей, поэтому мне не нужно писать строки и строки почти идентичного кода. Как ты делаешь. Родитель не содержит других элементов управления.

То, что я хочу сделать, - это просто иметь один обработчик событий в родительском UserControl, который выполняет и выполняет действия, которые может выполнять только родительский элемент управления (то есть условно вызывает событие, как событие, определенное в родительском элементе). Затем я бы подключил этот обработчик событий ко всем моим полям ввода в дочерних элементах управления, и дочерние элементы управления решат задачу анализа ввода и сообщат родительскому элементу управления, генерировать ли это событие. Хороший и чистый, без повторяющегося кода копирования-вставки (который для меня всегда приводит к ошибке).

Вот мой вопрос. Visual Studio думает, что я наполовину слишком умен, и предупреждает, что «метод CheckReadiness [обработчик события в родительском объекте] не может быть методом для события, поскольку класс, из которого этот класс является производным, уже определяет метод». Да, Visual Studio, в этом смысл . Я хочу, чтобы имел обработчик событий, который обрабатывает только события, выбрасываемые дочерними классами, и его единственная задача - дать мне возможность подключить детей без необходимости писать одну строку кода. Мне не нужны эти дополнительные обработчики - вся функциональность, которая мне нужна, естественно вызывается, когда дети обрабатывают вводимые пользователем данные.

Я не уверен, почему Visual Studio начал жаловаться на это сейчас (поскольку он позволил мне сделать это раньше), и я не уверен, как заставить это уйти. Предпочтительно, я хотел бы сделать это без определения метода, который просто вызывает CheckReadiness. Что вызывает это предупреждение, что вызывает его появление сейчас, когда оно не было час назад, и как я могу заставить его уйти, не прибегая к созданию маленьких обработчиков во всех дочерних классах?

Ответы [ 9 ]

7 голосов
/ 18 сентября 2008

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

base.checkReadyness(sender, e);

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

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

3 голосов
/ 19 февраля 2009

Я только что столкнулся с этим, я согласен, что такое чувство, что ты все делаешь правильно. Объявление метода виртуальным - это, в лучшем случае, обходной путь, а не решение.

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

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

2 голосов
/ 07 июня 2016

Я тоже столкнулся с этой проблемой, потому что в более ранних версиях VS вы могли «наследовать» обработчики событий. Таким образом, решение, которое я нашел без необходимости переопределять методы, заключается в простом назначении обработчика событий где-нибудь на этапе инициализации формы. В моем случае это сделано в конструкторе (я уверен, что OnLoad () также будет работать):

    public MyForm()
    {
        InitializeComponent();
        btnOK.Click += Ok_Click;
    }

... где обработчик Ok_Click находится в базовой форме. Пища для размышлений.

1 голос
/ 08 марта 2012

Я только что столкнулся с точной проблемой, которую впервые поднял Мерус, и, как и другие, которые публиковали ответы, мне не совсем понятно, почему в VS (я сейчас использую Visual C # 2010 Express) объектам для определения обработчика событий в базовом классе. Причина, по которой я публикую ответ, заключается в том, что в процессе решения проблемы, сделав код базового класса защищенным методом, который производные классы просто вызывают в своих (по существу пустых) обработчиках событий, я сделал переименование рефакторинга базы метод класса и заметил, что дизайнер VS перестал жаловаться. То есть он переименовал регистрацию обработчика событий (так что он больше не следовал соглашению дизайнера VS о присвоении имен обработчикам событий с ControlName_EventName), и это, казалось, удовлетворяло его. Когда я затем попытался зарегистрировать (теперь переименованный) обработчик базовых событий в элементах управления производного класса, введя имя в соответствующее событие VS, дизайнер создал новый обработчик события в производном классе, который я затем удалил, оставив зарегистрированным элемент управления производного класса. в метод базового класса (обработчик событий). Net, как и следовало ожидать, C # находит то, что мы хотим сделать законным. Это не нравится только дизайнеру VS, когда вы следуете соглашению с именами обработчиков событий дизайнера. Я не вижу необходимости, чтобы дизайнер работал таким образом. В любом случае, время продолжать.

0 голосов
/ 29 июля 2012

Вот что я сделал, чтобы базовые методы вызывались в нескольких похожих формах, каждая из которых имеет несколько дополнительных функций по сравнению с общими:

        protected override void OnLoad(EventArgs e)
    {
        try
        {
            this.SuspendLayout();
            base.OnLoad(e);

            foreach (Control ctrl in Controls)
            {
                Button btn = ctrl as Button;
                if (btn == null) continue;

                if (string.Equals(btn.Name, "btnAdd", StringComparison.Ordinal))
                    btn.Click += new EventHandler(btnAdd_Click);
                else if (string.Equals(btn.Name, "btnEdit", StringComparison.Ordinal))
                    btn.Click += new EventHandler(btnEdit_Click);
                else if (string.Equals(btn.Name, "btnDelete", StringComparison.Ordinal))
                    btn.Click += new EventHandler(btnDelete_Click);
                else if (string.Equals(btn.Name, "btnPrint", StringComparison.Ordinal))
                    btn.Click += new EventHandler(btnPrint_Click);
                else if (string.Equals(btn.Name, "btnExport", StringComparison.Ordinal))
                    btn.Click += new EventHandler(btnExport_Click);
            }

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

Обратите внимание, что вам может потребоваться выполнить тестирование на это. DesignMode, чтобы вы вообще пропустили код в VS Designer, но он работает нормально для меня даже без проверки.

0 голосов
/ 18 сентября 2008

Забудьте, что это обработчик событий, и просто сделайте правильное обычное переопределение метода в дочернем классе.

0 голосов
/ 18 сентября 2008

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

0 голосов
/ 18 сентября 2008

Эта статья о MSDN должна стать хорошей отправной точкой: Переопределение обработчиков событий с помощью Visual Basic .NET . Взгляните на Как раздел «Ручки» может вызвать проблемы в разделе «Производный класс» .

0 голосов
/ 18 сентября 2008

Если ваше событие уже определено в вашем родительском классе, вам не нужно переписывать его снова в своем дочернем классе. Это приведет к тому, что событие сработает дважды.

Убедитесь, что это то, что происходит. HTH:)

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