0

I have a custom UserControl (basically a fancy Button), and it needs to know when the control is enabled/disabled in order to change drawing colors.

I added a Shadows property in my control as follows:

Private _enabled As Boolean

Public Shadows Property Enabled() As Boolean
    Get
        Return Me._enabled
    End Get
    Set(value As Boolean)
        Me._enabled = value

        ' My code here to change the drawing colors

    End Set
End Property

This method seems to work fine when the my control is created using the GUI designer (pre-compile). However, when I dynamically create the control in runtime, the Get and Set code never runs.

Any ideas what could be causing this?

Jyclop
  • 469
  • 1
  • 6
  • 15
  • 1
    That's completely the wrong approach. What you should be doing is overriding the `OnEnabledChanged` method, which is what raises the `EnabledChanged` event. – jmcilhinney May 23 '21 at 08:23
  • + This is a runtime property. – dr.null May 23 '21 at 08:26
  • 1
    The fact that your code doesn't actually touch the base `Enabled` property suggests that you may not actually want the control to be genuinely disabled, but rather just your own logical version of being disabled. Is that true, or do you actually want Windows and .NET to see your control as disabled? If that is what you want then overriding `OnEnabledChanged` won't actually do what you want, because it will work with the existing `Enabled` property. – jmcilhinney May 23 '21 at 08:30
  • [Control's Enabled appearance at design time?](https://stackoverflow.com/questions/25162260/controls-enabled-appearance-at-design-time). – dr.null May 23 '21 at 09:02
  • [How can I gray-out a disabled PictureBox used as Button?](https://stackoverflow.com/a/61584671/7444103) – Jimi May 23 '21 at 09:38

1 Answers1

1

It's hard to know for sure because you haven't provided enough information but I suspect that I know what the issue is. When you shadow a member, you MUST access that member via a reference of the derived class in order to invoke the derived implementation. If you use a reference of the base type then it is the base implementation that you will invoke. That is different to when you override a member, in which case the derived implementation will be invoked regardless of the type of the reference. I generally summarise this as overriding following the type of the object while shadowing follows the type of the reference. Try running this code to see that in action:

Module Module1

    Sub Main()
        Dim dc As New DerivedClass

        dc.OverrideMethod()
        dc.ShadowMethod()

        Dim bc As BaseClass = dc

        bc.OverrideMethod()
        bc.ShadowMethod()
    End Sub

End Module

Public Class BaseClass

    Public Overridable Sub OverrideMethod()
        Console.WriteLine("BaseClass.OverrideMethod")
    End Sub

    Public Sub ShadowMethod()
        Console.WriteLine("BaseClass.ShadowMethod")
    End Sub

End Class
Public Class DerivedClass
    Inherits BaseClass

    Public Overrides Sub OverrideMethod()
        Console.WriteLine("DerivedClass.OverrideMethod")
    End Sub

    Public Shadows Sub ShadowMethod()
        Console.WriteLine("DerivedClass.ShadowMethod")
    End Sub

End Class

Here is the output:

DerivedClass.OverrideMethod
DerivedClass.ShadowMethod
DerivedClass.OverrideMethod
BaseClass.ShadowMethod

As you can see, calling the shadowed method via a reference of the base type invokes the base implementation, while calling the overridden method via a reference of the base type invokes the derived implementation.

In your specific case, when you added the instance at run time, you had no field of the control's specific type to access it by, so you probably accessed it via the Controls collection of the form. That would return a Control reference so, if you were to access the Enabled property via that, it would be the base implementation you invoked. If you want to invoke your derived implementation then you'd need to cast that reference as the actual type of your control. One option for doing so is to use the OfType method to filter by type and cast at the same time, e.g.

Dim firstFancyButton = Controls.OfType(Of FancyButton)().First()

Otherwise, perform an explicit cast, e.g.

Dim firstFancyButton = DirectCast(Controls("FancyButton1"), FancyButton)
jmcilhinney
  • 50,448
  • 5
  • 26
  • 46