m.r.m.40 Ответов: 2

Windowsform и uercontrol, реализуя в них изменения.


Привет,

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

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

Public Class BaseForm
    Inherits System.Windows.Forms.Form

    Protected Overrides Sub OnVisibleChanged(e As System.EventArgs)
        MyBase.OnVisibleChanged(e)

        If Me.Visible Then ' create Handler to each Button when Form is shown (becomes visible)
            For Each myControl As Control In Me.Controls
                If myControl.GetType Is GetType(Button) Then
                    AddHandler myControl.Click, AddressOf TestModul.ClickHandler
                End If
            Next
        Else ' remove Handler from each Button when Form is left (becomes unvisible)
            For Each myControl As Control In Me.Controls
                If myControl.GetType Is GetType(Button) Then
                    RemoveHandler myControl.Click, AddressOf TestModul.ClickHandler
                End If
            Next
        End If

    End Sub
End Class


Тестовый модуль выглядит следующим образом:

Module TestModul
    Public Sub ClickHandler(sender As Object, e As System.EventArgs)

        Dim mySender As Control = sender
        MessageBox.Show(mySender.Name + vbCrLf + mySender.Parent.Name)
        If (mySender.Parent.GetType().ToString().Contains("UserControl")) Then
            MessageBox.Show("Its a user control")
        End If

    End Sub
End Module

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

Public Class BaseUserControl
    Inherits System.Windows.Forms.UserControl

   Protected Overrides Sub OnVisibleChanged(e As System.EventArgs)
        MyBase.OnVisibleChanged(e)

        If Me.Visible Then ' create Handler to each Button when Form is shown (becomes visible)
            For Each myControl As Control In Me.Controls
                If myControl.GetType Is GetType(Button) Then
                    AddHandler myControl.Click, AddressOf TestModul.ClickHandler
                End If
            Next
        Else ' remove Handler from each Button when Form is left (becomes unvisible)
            For Each myControl As Control In Me.Controls
                If myControl.GetType Is GetType(Button) Then
                    RemoveHandler myControl.Click, AddressOf TestModul.ClickHandler
                End If
            Next
        End If

    End Sub

End Class


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

Что я уже пробовал:

как прослеживается он не входит в это состояние,

If myControl.GetType Is GetType(Button) Then


и видите это как ложное условие. Я удалил оператор If и снова увидел, что он не читает строку кода
AddHandler myControl.Click, AddressOf TestModul.ClickHandler

так что опять же изменение не будет сделано на кнопках.

Well in on of my forms it's working, because I opened it and manually removed the line of inheritence after the name of those classes, I just removed the line ' Inherits baseusercontrol' and rewrote it. then it worked.


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


Заранее благодарю вас за вашу помощь.

m.r.m.40

Коды выше даны мне профессиональным членом "Ральф Мейер".

Richard MacCutchan

Тогда вам следует обратиться за помощью к Ральфу Мейеру.

m.r.m.40

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

Richard MacCutchan

Вернитесь к сообщению, где он дал вам этот код.

0x01AA

Ваш UserControl, вероятно, не является контейнером для кнопки.

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

BillWoodruff

Проверьте, находятся ли кнопки в UserControl на "поверхности" UserControl (содержащейся в коллекции ControlCollection UserControl). Если некоторые или все кнопки находятся внутри других ContainerControls, вы не получите к ним доступ через Me.Controls ... вместо того, чтобы использовать меня.Контроля.Найти с помощью рекурсивного параметра установлено в значение true.

Ralf Meier

Я бы не стал добавлять этот код в usercontrol. Я бы сделал это в той форме, как описано. Когда вы перебираете коллекцию Forms. control, вы также можете проверить, есть ли в каждом из этих элементов управления также дочерние элементы управления-в этом случае вы проверяете дочерние элементы управления и подключаете их (при необходимости) также к обработчику. См. мое решение (2) на этот счет ...

Philippe Mori

Зачем вам добавлять / удалять обработчик в соответствии с видимостью? Как бы вы нажали на невидимую кнопку?

m.r.m.40

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

Philippe Mori

И вы не ответили на вопрос... Похоже, вы скопировали чужой бедный код!

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

Ralf Meier

Код-внушение исходит от меня ...
Я выбрал метод OnVisibleChanged-для добавления и удаления обработчиков, потому что этот метод находится непосредственно в команде Form.show и/или Form.hide. По-моему, я удаляю ненужные соединения. Конечно, можно также соединить обработчики с формой.OnHandleCreated и удалить его по форме.Онхандледестройед. Есть несколько вариантов-я выбрал именно этот.

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

2 Ответов

Рейтинг:
0

0x01AA

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

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

[Редактировать]
Наконец: более сложный (но, вероятно, правильный) способ описан здесь на CP Проектирование Вложенных Элементов Управления[^]

Надеюсь, это поможет.

[Edit1] История OnVisible
Примечание: Я бы посоветовал избегать частого добавления и удаления обработчиков событий, как это делается в вашем коде. Вместо этого вы должны попробовать проверить parent.Visible в вашем обработчике событий.

Вот идея, как вы можете решить запрос "OnVisible" как поведение по умолчанию вашего элемента управления. Я сделал это на c# (я не знаю VB), но я уверен, что для вас не проблема преобразовать его в VB.

 public partial class MyPanel : Panel // ContainerControl //UserControl
 {
     Form lastParent= null;

     // Install Event handler to the control
     protected override void OnParentChanged(EventArgs e)
     {
         // Call base class
         base.OnParentChanged(e);

         // Remove handler from previous hosting form
         if (lastParent != null)
         {
             lastParent.VisibleChanged -= ParentVisibleChanged;
             lastParent = null;
         }

         // Find the new hosting form. Most probably the same, but who knows
         Control parent = this.Parent;
         while (parent != null)
         {
             if (parent is Form)
             {
                 lastParent = (Form)parent;
                 lastParent.VisibleChanged += ParentVisibleChanged;
                 break;
             }
             parent = parent.Parent;
         }
     }

     protected void ParentVisibleChanged(object sender, EventArgs e)
     {
         // Debug only
         MessageBox.Show("ParentVisibleChanged");

         // Do what you need to do for form visible change
         // Should always be true.
         if (lastParent != null)
         {
             if (lastParent.Visible)
             {
             }
             else
             {
             }
         }
     }
  ...
  .....
}


Ralf Meier

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

0x01AA

Наверное, вы правы, мне нужно еще раз подумать об этом. Спасибо, что разбудил меня по этому вопросу.

BillWoodruff

+5
к вашему сведению: это элементы управления, которые наследуются от ContainerControl:

            Система.Окна.Форм.Форма
            Система.Окна.Формы.Сетки
            Система.Окна.Формы.Класса splitcontainer
            Система.Окна.Формы.ToolStripContainer
            Система.Окна.Формы.Панель инструментов
            Система.Окна.Формы.UpDownBase
            Система.Окна.Формы.элемент управления UserControl

цепочка наследования для панели:

Система.Объект
  Системы.Класса MarshalByRefObject
    Система.ComponentModel.Компонент
      Система.Окна.Формы.Контроль
        Система.Окна.Формы.ScrollableControl
          Система.Окна.Формы.Панель
            Система.Окна.Формы.Дизайн.ComponentEditorPage
            Система.Окна.Формы.Управления flowlayoutpanel
            Система.Окна.Формы.Сплиттерпанель
            Система.Окна.Формы.Управления tablelayoutpanel
            Система.Окна.Формы.Новые
            Система.Окна.Формы.ToolStripContentPanel

0x01AA

Большое спасибо.

Рейтинг:
0

Ralf Meier

Я бы изменил опубликованные методы следующим образом :

Protected Overrides Sub OnVisibleChanged(e As System.EventArgs)
        MyBase.OnVisibleChanged(e)

        CheckControlCollection(Me , Me.Visible)

End Sub


Private Sub CheckControlCollection(myHost As Control , state as boolean)
        For Each myControl As Control In myHost.Controls
            If myControl.GetType Is GetType(Button) Then
                if state then AddHandler myControl.Click, AddressOf TestModul.ClickHandler
                if not state then RemoveHandler myControl.Click, AddressOf TestModul.ClickHandler
            End If

            If myControl.Controls.Count > 0 Then
                CheckControlCollection(myControl , state) ' <- I have modified this line because of a mistake in it ...
            End If
        Next
End Sub


Но обратите внимание-этот код не тестируется ...
Оба метода по-прежнему принадлежат вашей базовой форме. Вам не нужно, чтобы интегрировать его в пользовательский элемент управления или любая другая containercontrol.
Ваш код в вашем usercontrol не работает, потому что usercontrol не изменяет его видимое состояние. Если вы хотите сделать это в usercontrol таким же образом, вы должны переопределить другой метод - но я предпочитаю этот способ ...

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

Дополнительно (2) :
&ГТ;&ГТ; я изменил код, потому что ошибка в нем ...


Дополнительный (3) - модифицированный ClickHandler :
Public Sub ClickHandler(sender As Object, e As System.EventArgs)

    Dim mySender As Control = sender
    Dim myChildPath As String = mySender.Name

    Do
        If mySender.Parent Is Nothing Then Exit Do
          mySender = mySender.Parent
        myChildPath += vbCrLf + mySender.Name
    Loop

    MessageBox.Show(myChildPath)

End Sub


m.r.m.40

Спасибо, но нет, это не работает на usercontrols.

Ralf Meier

Думаю, вы меня неправильно поняли. Этот код не предназначен для работы с usercontrols - он должен работать также и с формой (base -). Он заменяет образцы кода, которые я дал вам в другом вопросе ...

Вы действительно хотите, чтобы такой код работал на usercontrols ?

m.r.m.40

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

Ralf Meier

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

Пожалуйста, приведите мне пример для вашего вопроса ...

m.r.m.40

Что-то пришло мне в голову,

Эти строки кода:

Если Я ... Виден Тогда
CheckControlCollection(Me, Me.Visible)
Ещё
CheckControlCollection(Me, Me.Visible)
Конец, Если

не нужны утверждения "если" и "еще". одна строка
CheckControlCollection(Me, Me.Visible)
будет работать так же.

Ralf Meier

Да... вы правы - я никогда этого не видел-извините.
Но как насчет твоей проблемы ? Вы продвинулись еще на шаг ? Или как я могу вам помочь ?..

m.r.m.40

Я все еще работаю над этим,
Это форма, унаследованная от базовой формы под названием "MainForm", внутри нее есть панель под названием "Panel1", пользовательские элементы управления открыты внутри панели. и код, который вы мне дали, не работает на этой форме и usercontrols, которые открываются внутри нее, однако они правильно работают с формами другого проекта в качестве тестового prject.

Ralf Meier

Привет,
расскажи мне что-нибудь о своем состоянии ...
Вы видели мои последние изменения (3 дня назад) в коде ?

m.r.m.40

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

m.r.m.40

Я думаю о том, чтобы переопределить функцию onload system.windows.forms.form и внутри нее поместить код, выше которого вы мне дали. поэтому каждый раз, когда форма загружается, она добавляет обработчик к кнопкам внутри нее. вы согласны с этим?

Ralf Meier

Возможно...
Если вы посмотрите на класс Form, вы найдете много методов событий, которые принадлежат ему.
например :
OnHandleCreated-OnHandleDestroyed : когда экземпляр формы создается / утилизируется
OnVisibleChanged (как я уже описал) поставляется вместе с формой.Показать и сформировать. скрыть
Возможно, также OnActivated-OnDeActivated

Вы должны посмотреть, какой метод лучше всего соответствует тому, что вы хотите сделать.
Как я уже описал : обычно я удаляю обработчики событий, когда они больше не нужны. Если вы скрываете свою форму, они больше не нужны - поэтому я бы их удалил. Но это также не ошибка, если вы сохраняете их живыми, потому что, если форма скрыта, она не может вызвать никакого события. Но вы должны знать : каждый обработчик, созданный вами вручную, должен быть удален вами вручную. Если вы забудете об этом, это может иметь "интересные" эффекты - возможно, сборщик мусора не освобождает память, и части функции все еще активны ...

Ralf Meier

неважно... если бы я действительно мог тебе помочь ...

BillWoodruff

+5

Ralf Meier

Спасибо, Билл ... :)

m.r.m.40

Привет Ральф,

Я исправил это с помощью приведенной ниже функции

Защищенные Переопределения Sub InitLayout()

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

Спасибо вам за всю ту поддержку, которую вы мне оказали.

Ralf Meier

Конечно... ты мог бы. Но, пожалуйста, помните : одним из первых советов, которые я вам дал, было : "если вы хотите использовать его в UserControl, вы должны переопределить различные методы событий".

Но... из-за большого количества комментариев Ан пытается ответить : какова ваша конечная цель ? Это только для тестирования и / или изучения того, как это работает ... или есть другая причина ?

m.r.m.40

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

Спасибо за помощь.