Вопрос

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

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

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

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

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

Это было полезно?

Решение

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

base.checkReadyness(sender, e);

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

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

Другие советы

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

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

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

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

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

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

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

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

Обязательно проверьте, действительно ли это происходит.HTH :)

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

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

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

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

        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, но у меня он отлично работает даже без проверки.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top