Enhancing ContainerControl

· Dec 26, 01:28 PM

The Canvas and ContainerControl classes provide no hook to implement behavior when they are hidden. For Mac OS composited windows in particular, this makes it more difficult to implement custom controls. But with a bit of work, it is possible to add your own hooks.

The hooks I would like are events VisibilityChanging and VisibilityChanged. For ContainerControl, this is almost straightforward; it has methods Show and Hide, inherited from Window. So we define a subclass BetterContainerControl of ContainerControl; note that this should be something created with ‘New Class’, not ‘New ContainerControl’.

Next, we add event definitions

Sub VisibilityChanging()

and

Sub VisibilityChanged()

to BetterContainerControl.

Then we override Show and Hide to call the event handlers.

Sub Show()
  if me.Visible then
    return
  end if
 
  VisibilityChanging
  super.Show
  VisibilityChanged
End Sub
Sub Hide()
  if not me.Visible then
    return
  end if
 
  VisibilityChanging
  super.Hide
  VisibilityChanged
End Sub

Unfortunately, a feedback prevents this code from compiling.

A workaround is to cast the reference me to Window, and call Show/Hide on it. Here is the code for Show.

Sub Show()
  if me.Visible then
    return
  end if
 
  VisibilityChanging
  Window(me).Show
  VisibilityChanged
End Sub

Perhaps you’re wondering why this does not result in a StackOverflowException; I can only suppose that it is a consequence of the problem that causes us to resort to this trick. For now, it works.

And now, a quick test; add a new ContainerControl, named ContainerControl1, to a project, and set its superclass to BetterContainerControl. Drop one into a window, add some beeps to the VisibilityChanging and VisibilityChanged event handlers.

Add a PushButton to the window, and implement its Action event handler.

Sub Action()
  if ContainerControl11.Visible then
    ContainerControl11.Hide
  else
    ContainerControl11.Show
  end if
End Sub

A quick test run shows that this all works. Now I replace the code above with

Sub Action()
  ContainerControl11.Visible = not ContainerControl11.Visible
End Sub

and test again — no beeps. There is a faint smell of code duplication coming from the Rb framework; perhaps Hide, Show and Visible.Set are not calling the same code.

Unfortunately, we cannot override ContainerControl.Visible because it is a computed property. What we can do, however, is shadow it.

Property Visible As Boolean
Get
  return ContainerControl(me).Visible
End Get
Set
  if value = me.Visible then
    return
  end if
   
  if value then
    me.Show
  else
    me.hide
  end if
End Set

The result is a ContainerControl with events to be implemented when its visibility is changed.

We can do the same for Canvas: write a subclass, add the event definitions, and add a computed property Visible that shadows Canvas.Visible.

Property Visible As Boolean
Get
  return Canvas(me).Visible
End Get
Set
  if value = me.Visible then
    return
  end if
   
  VisibilityChanging
  Canvas(me).Visible = value
  VisibilityChanged
End Set

With this, you can now get custom controls on windows to be hidden when they should be.

---

Comment

  1. Thanks for writing this. I’ve often needed this.

    BTW, I doubt that it’s the feedback that’s causing the first attempt not to compile – it’s rather the bug that’s responsible for it :o)

    Thomas Tempelmann · Dec 26, 04:59 PM · #

Commenting is closed for this article.