Когда Я не Я

Хакер дает советы, раскрывает секреты и делится своими мыслями по поводу программирования.

Модератор: Хакер

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Когда Я не Я

Сообщение Хакер » 31.07.2009 (Пт) 21:40

  • Есть один момент, с которым сталкиваются многие новички, о котором я бы хотел рассказать.
  • Как известно, в VB переменная Me внутри методов класса содержит ссылку на объект, метод которого был вызван. Чуть более продвинутые знают, что при вызове методов COM-объектов эта ссылка неявно передаётся как параметр метода.
  • Пусть у вас есть некоторый класс Class1, имеющий метод Test:
    Код: Выделить всё
    Public Sub Test(ByVal AlternativeMe As Object)
         If Me Is AlternativeMe Then
             msgBox "[Me] и [AlternativeMe] тождественны!"
         End If
    End Sub
  • Если мы сделаем что-то вроде этого:
    Код: Выделить всё
    Dim x as Class1
    Set x = New Class1
    x.Test x
    мы увидим сообщение «[Me] и [AlternativeMe] тождественны!», что логично.
  • Но всегда ли так? И да, и нет. Вообще, строго говоря, это всегда так. Но бывают случаи, когда вам кажется, что этот «закон не выполняется». Создайте элемент управления (UserControl), пусть он называется UCTest, поместите в него ровно тот же метод Test. На форме нарисуйте UCTest1 и сделайте что-то вроде этого:
    Код: Выделить всё
    Private Sub Form_Load()
        UCTest1.Test UCTest1
    End sub
  • Никакого сообщения вы не увидите. Как это возможно? Так происходит, потому что Me в контексте метода Test ссылается на один объект, а UCTest1 в контексте кода формы — на другой. «Закон», на самом деле, по прежнему работает, просто теперь у вас два объекта: внешний, доступный из формы, и внутренний, доступный через Me внутри UserControl'а. Внешний является обёрткой над внутренним, повторяя все члены внутреннего.

    А какая разница?
    Разница есть, и она ощутимая. Если внешний объект обладает всеми возможностями внутреннего, то внутренний всеми возможностями внешнего не обладает. Примеры? Пожалуйста:
  • В коде формы вы можете написать что-то подобное:
    Код: Выделить всё
    UCTest1.Top = 0
    UCTest1.Left = 0
    В самом же контроле сделать то же самое:
    Код: Выделить всё
    Me.Top = 0
    Me.Left = 0
    вам никак не под силу — ну нет у внутреннего объекта свойства Top, Left, Height, Width.
  • У внутреннего объекта есть и другие ограничения. Например, он не может быть назначен контейнером. Пусть у вас есть кнопка Command1 на форме. Вы можете сделать так, что кнопка будет лежать не на форме, а внутри вашего контрола:
    Код: Выделить всё
    Private Sub Form_Load
        Set Command1.Container = UCTest1
    End Sub

    Но вы не сможете перенести эту функциональность в сам контрол, сделав так:
    Код: Выделить всё
    Public Sub SetAsContainerOf(ByVal child As Control)
        Set child.Container = Me
    End Sub

    Код: Выделить всё
    Private Sub Form_Load
         UCTest1.SetAsContainerOf Command1
    End Sub

    Этот код не будет работать.

    Есть ли какая-то связь?
  • Связь между внутренним и внешним объектом к счастью есть. Поэтому все рассмотренные выше задачи решить всё-таки можно. Получить ссылку на внутренний объект, имея ссылку на внешний — легко. Равно как и легко из UserControl-а получить ссылку на внешний.
  • Несмотря на это, многие получают эту ссылку извращенским способом: либо явно передают ссылку на внешний объект в метод контрола, либо внутри контрола ищут ссылку на внешний объект в UserControl.Parent.Controls.
  • Получить из внешнего мира ссылку на врутренний объект легко: если вы внимательно смотрели на члены внешних объектов контролов, вы наверное замечали там свойство Object.Это свойство внешнего не что иное как, как ссылка на внутренний объект.
  • Получить из UserControl-а ссылку на внешний объект так же легко: у объекта UserControl есть свойство Extender и это не что иное, как ссылка на внешний объект (он правильно называется extender-ом)
  • То, что это именно те ссылки легко убедиться:
    Код: Выделить всё
    ' В контроле:
    Public Sub Test(byval oExternal as Object, Byval oInternal as object)
        MsgBox oExternsl Is UserControl.Extender
        Msgbox oInternal Is Me   
    End Sub


    Вы увидите два раза подряд True:
    Код: Выделить всё
    Private Sub Form_Load
        UCTest.Test UCTest, UCTest.Object
    End Sub

  • Зная это, вы легко можете двигать (свойства Top, Left есть у UserControl.Extender) или делать контейнером других контролов самого себя.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Когда Я не Я

Сообщение ger_kar » 30.05.2016 (Пн) 6:51

Кроме, упомянутых объектов, есть еще и непосредственно сам объект класса UserControl самый нижний в иерархии и таким образом получается, что контрол представляет собой слоеный пирог или матрешку. На на самом глубоком уровне залегает UserControl, далее идет сама обертка, которую создает пользователь, создающий свой элемент, и уже над ним идет оболочка контейнер в виде Extender'-а, который имеет класс VBControlExtender и тут возникает множество следующих вопросов:
1) Во первых так это или нет, то что я написал про пирог, сдается мне что так, но не совсем, так как свойство Extender это свойство предоставляемое классом UserControl и значит получается что с одной стороны пользовательский код это оболочка над UserControl, а с другой стороны они как бы параллельно идут.
2) Является ли этот Extender неотъемлемой частью самого контрола, или же это промежуточный элемент, в который VB заботливо оборачивает каждый создаваемый экземпляр любого контрола (или подкладывает под контрол). Т.е. является ли этот пирог монолитным, или подложка это отдельный промежуточный объект создаваемый в момент размещения контрола
3) Из первых двух вытекает следующий вопрос: Это фишка с (Extender'-ом) исключительно VB6-шная фича, или любой контрол, используемый и создаваемый в рамках технологии ActiveX, будет обладать такими свойствами? Т.е. если VB'-шный контрол будет использоваться в другом приложении, создаваемом в другой среде, то будет ли у этого контрола такой же Extender и если да, то какого класса? Понятно, что раз есть у контрола свойство Extender, то оно и в другом месте никуда не денется и также возвратит ссылку на некий объект, но вот что это будет, тут вопрос.
Если контрол например будет менять свои размеры, то такой код все среды VB будет работать или обломится? И если например контрол предполагает множество операций со своим Extender'-ом, то можно сохранить на него ссылку, но контрол может переместиться на другой контейнер и ссылка будет не валидной, а может он переезжает вместе с Extender'-ом и тогда все будет ОК. Ссылку можно объявить как Object, а можно и VBControlExtender. Но тогда в другой среде, может быть Extender', но другого класса и код обломается.
Бороться и искать, найти и перепрятать


Вернуться в МануAll

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1

    TopList