StrataFrame Forum

SubClass SF Button

http://forum.strataframe.net/Topic28558.aspx

By Terry Bottorff - 10/2/2010

It is time I increase my skill level. So I want to learn how to subclass some of the SF controls. I want to start with the SF Button. I have been able to subclass the button and have it show up in the toolbox. I can drag it to a form and it works like a normal SF button. But now I want to set it size, text and change the click event. I can not seem to find the correct syntax so I need a little nudge to get me going.  I think one thing I need to do is an click override but I can not seem to find a sample and not sure how to set the size and text. TIA.
By Greg McGuffey - 10/4/2010

Terry,

To override the size, I'd use the contstructor:

Public Sub New()
  '-- Call base constructor.
  MyBase.New()

  '-- Set default height/width.
  Me.Height = 32
  Me.Width = 75
End Sub


To set the click behavior, override the OnClick sub.

Protected Overrides Sub OnClick(e As EventArgs)
  '-- Add custom logic to happen before clicks are handled

  '-- Call base class (this raises the click event for consumers)
  MyBase.OnClick(e)

  '-- Add custom logic to happen after clicks are handled.
End Sub
By Terry Bottorff - 10/4/2010

Thank you very much.
By Terry Bottorff - 10/5/2010

Finally got back to this but am having problems.

''' <summary>
''' My Button class.  I will use this class to exit a form.
''' </summary>
''' <remarks></remarks>
<ToolboxBitmap(GetType(System.Windows.Forms.button))>
Public Class myExitButton
    Inherits MicroFour.StrataFrame.UI.Windows.Forms.Button

    Public Sub New()
        MyBase.New()
        Me.Width = 23
        Me.Height = 32
        Me.Text = "Exit"
    End Sub

    Protected Overrides Sub OnClick(ByVal e As System.EventArgs)
        MyBase.OnClick(e)
        ' Simply Want to Close the Form Like
        ' Me.close()
    End Sub
Of course the three things I want to work don't:
  1. The icon of a button does not show up just a cog wheel on the toolbox. Maybe that is the way it should be.
  2. Me.Close will not work
  3. me.text="Exit' does not show up.
TIA

By Greg McGuffey - 10/5/2010

I haven't tried to do this in VS yet, but here's somethings to try. If these don't work, I'll open the IDE. BigGrin

1. It's possible that the attribute is case sensitive (cause everything else looks good). So
<ToolboxBitmap(GetType(System.Windows.Forms.Button))>


2. Me.Close attempts to close the button...oops.  You'd need to user the Parent property. Of course this isn't that straight forward as the button might be in a panel. So you need to walk up the parents until you get to a form, then close that.

3. I'd try the OnCreateControl method then (override it) rather than the constructor.
By Terry Bottorff - 10/6/2010

1. Button vs button did not make any difference.
2. parent.close() did not work but parent.dispose() seems to work. Would dispose() create any problems if I know that I am going to drop this control on my forms only?
3. I am going to have to research OnCreateControl Method since I have not run across that method before. I may need some help here.

Thank you again for your help and expert advise.
By Terry Bottorff - 10/6/2010

Protected Overrides Sub oncreatecontrol()
        MyBase.OnCreateControl()
        Me.Text = "Exit"
    End Sub

This is what I used and it seems to work fine. Now the icon?
Wow what a great deal to digest today. 

By Greg McGuffey - 10/6/2010

I'm still not sure why the icon isn't working. If I get time today I'll see if I can work up an example.

As to Me.Parent.Close() vs. Me.Parent.Dispose(), this has to do with the Type of the Parent property. The Parent property is of Type System.Windows.Forms.Control. Winform Forms inherit from this Type (yep, forms are sub-classes of the basic Control Type, just like buttons or text boxes).  All Controls implement IDisposable (which has a Dispose method).   So, once you find the parent form, you'll want to cast it to a Form, then call close.

Protected Overrides Sub OnClick(e As EventArgs)
  MyBase.OnClick(e)

  '-- Get the parent form.
  Form parentForm = Me.GetParentForm()
  If parentForm IsNot Nothing
    parentForm.Close()
  End If
End Sub

''' <Summary>
''' Find and return the parent form of this control.
''' </Summary>
Private Sub GetParentForm()
  '-- Establish a return var.
  Form parentForm = Nothing

  '-- Establish local to track current parent we're testing.
  Control currentParent = Me.Parent

  '-- Walk parent hierarchy until we run out of parents or we find a form.
  While currentParent IsNot Nothing
    '-- Test if the parent is a Form.
    If currentParent.GetType() Is GetType(Form) Then
      parentForm = DirectCast(currentParent, Form)
      Exit While
    End If

    '-- Get the next parent.
   
currentParent = currentParent.Parent
  End While

  '-- Return the parent form (or null if one isn't found)
  Return parentForm
End Sub


I just typed this code in, so there could be errors, but it should get you going in the right direction.
By Terry Bottorff - 10/6/2010

Protected Overrides Sub OnClick(ByVal e As System.EventArgs)
        MyBase.OnClick(e)
         Dim parentform As Form = Me.GetParentForm()

        If parentform IsNot Nothing Then
            parentform.Close()
        End If

    End Sub

    Protected Overrides Sub oncreatecontrol()
        MyBase.OnCreateControl()
        Me.Width = 75
        Me.Height = 23
        Me.Text = "Exit"
    End Sub

    Private Function GetParentForm() As Object
        ' return var
        Dim parentform As Form = Nothing
        Dim ctl1 As Control = Me.Parent

        If TypeOf ctl1 Is Form Then
            parentform = DirectCast(ctl1, Form)
            Return parentform
        End If

        Do
            ctl1 = Me.GetNextControl(ctl1, True)

            If ctl1 IsNot Nothing Then
                ' Search for Form
                If TypeOf ctl1 Is Form Then
                    parentform = DirectCast(ctl1, Form)
                End If

            End If

        Loop Until ctl1 Is Nothing

        Return parentform

    End Function
The above works but of course I am sure I did not do it the best way. Any suggestions would be appreciated.
Thank you again.


By Greg McGuffey - 10/6/2010

Looking good. I played around with another option, which is to simply add a property to the CloseButton, so you can set the parent form manually. This simplifies the code and potentially could run faster, but you have to remember to set the parent form. The code using this looks like:

public class CloseButton
  : System.Windows.Forms.Button
{

  private System.Windows.Forms.Form _parentForm;

  /// <summary>
  /// Defines.
  /// </summary>
  public System.Windows.Forms.Form ParentForm
  {
    get
    {
      return _parentForm;
    }
    set
    {
      _parentForm = value;
    }
  }

  protected override void OnCreateControl()
  {
    base.OnCreateControl();

    this.Text = "Close";
    this.Width = 75;
    this.Height = 23;
  }

  protected override void OnClick( EventArgs e )
  {
    base.OnClick( e );

    //-- Close the form if its set.
    if (this.ParentForm != null)
    {
      this.ParentForm.Close();
    }
  }
}


So this code is simpler but requires that you remember to set the ParentForm property. I'd likely go with your original code as usually the close button won't be buried too deep in a form's control hierarchy, so the time for the loop should be negligible.

I also played around with the icon and had no luck either. I checked the SF source code and they are using exactly what you are using....and the SF button has a nice icon.... Crazy
By Terry Bottorff - 10/6/2010

Thanks for the encouragement. 
If you are able to find any more out about the Icon please let me know. 
I will try your method of having a property just so I have that experience.
I know your time is valuable and I appreciate it very much.
By Greg McGuffey - 10/6/2010

Glad it helped!