McBasic™Get McBasic™ ↗
Build 881
Hands-on tutorial · Extensions

Author a reusable BASIC control

Compose child controls behind public properties and a custom event.

2 Form / control designs2 complete BASIC filesGuided sample project

CustomerId and CustomerName hide the internal TextBoxes behind a public property contract. OpenRequested communicates intent without forcing the consumer to know the inner button’s name. Do not expose every child control merely because it exists; keep a small stable API.

Step 1Prepare a safe practice project#

Extract the archive into a new writable folder, separate from your own application. Open CustomerCard.mcproj in McBasic™. Keep every declared source, layout, resource and migration file together.

To reconstruct it yourself, create a UserControlLibrary project and add the files declared below. In the complete project, follow these steps as a guided rebuild: replace each named source file once and Check after all its procedures are present.

Exact project configuration
CustomerCard.mcproj
{
  "schemaVersion": 1,
  "projectId": "8c8e4e3f-3e45-4b7e-9a57-7b1e82e2b233",
  "name": "CustomerCard",
  "kind": "UserControlLibrary",
  "language": {
    "dialect": "McBasic1",
    "requireExplicit": true,
    "compare": "Binary",
    "defaultArrayBase": 0
  },
  "package": {
    "packageId": "com.mcbasic.samples.customercard",
    "version": "1.0.0",
    "minimumMcBasicVersion": "0.1.0",
    "vendor": "McBasic Samples",
    "description": "Two composed BASIC user controls.",
    "assemblyPath": "lib/net10.0/CustomerCard.dll",
    "licenseSpdx": "MIT",
    "licensePath": "licenses/LICENSE.txt"
  },
  "forms": [],
  "userControls": [
    {
      "id": "customer-card",
      "typeName": "CustomerCard",
      "layout": "Controls/CustomerCard.form.json",
      "code": "Controls/CustomerCard.bas"
    },
    {
      "id": "customer-badge",
      "typeName": "CustomerBadge",
      "layout": "Controls/CustomerBadge.form.json",
      "code": "Controls/CustomerBadge.bas"
    }
  ],
  "modules": [],
  "classes": [],
  "tests": [],
  "references": [],
  "resources": [],
  "targets": [
    "osx-arm64"
  ],
  "capabilities": []
}

Step 2Build the Form and set its properties#

CustomerCard

Select the Form first and set its properties. Add containers before their children. These are initial Designer values, not statements to paste into a procedure.

Form propertyValue
Caption"Customer Card"
Width320
Height120
MinWidth160
MinHeight80
TypeNameParent
LabellblIdForm
TextBoxtxtIdForm
LabellblNameForm
TextBoxtxtNameForm
CommandButtoncmdOpenForm
lblId · exact Inspector values
PropertyValue
Left16
Top12
Width80
Height28
Caption"Customer ID"
txtId · exact Inspector values
PropertyValue
Left104
Top8
Width92
Height32
Text""
ReadOnlyFalse
MultiLineFalse
WordWrapFalse
lblName · exact Inspector values
PropertyValue
Left16
Top56
Width80
Height28
Caption"Name"
txtName · exact Inspector values
PropertyValue
Left104
Top52
Width92
Height32
Text""
ReadOnlyFalse
MultiLineFalse
WordWrapFalse
cmdOpen · exact Inspector values
PropertyValue
Left208
Top52
Width96
Height32
Caption"Open"

CustomerBadge

Select the Form first and set its properties. Add containers before their children. These are initial Designer values, not statements to paste into a procedure.

Form propertyValue
Caption"Customer Badge"
Width240
Height96
MinWidth160
MinHeight72
TypeNameParent
TextBoxtxtBadgeForm
CommandButtoncmdTapForm
txtBadge · exact Inspector values
PropertyValue
Left12
Top12
Width136
Height32
Text"Badge"
ReadOnlyFalse
MultiLineFalse
WordWrapFalse
cmdTap · exact Inspector values
PropertyValue
Left156
Top12
Width72
Height32
Caption"Tap"

Step 3Connect the events explicitly#

CustomerCard

ObjectEventProcedureParameters
txtIdChangetxtId_ChangeChange()
txtNameChangetxtName_ChangeChange()
cmdOpenClickcmdOpen_ClickClick()

CustomerBadge

ObjectEventProcedureParameters
txtBadgeChangetxtBadge_ChangeChange()
cmdTapClickcmdTap_ClickClick()

Step 4Enter the complete behavior#

Open the named source file. Enter declarations first, then every procedure. Expand a procedure for its full body, or copy the complete file. Helpers are required: do not stop after entering the first Click handler.

Controls/CustomerCard.bas

Enter these declarations at file scope, before the procedures.

Controls/CustomerCard.bas · declarations
Option Explicit

Public Event OpenRequested()
Public Property Get CustomerId() As String

Keep this public property accessor with its complementary accessor and the fields or controls it uses.

Controls/CustomerCard.bas · CustomerId
Public Property Get CustomerId() As String
    CustomerId = txtId.Text
End Property
Public Property Let CustomerId(ByVal value As String)

Keep this public property accessor with its complementary accessor and the fields or controls it uses.

Controls/CustomerCard.bas · CustomerId
Public Property Let CustomerId(ByVal value As String)
    txtId.Text = value
End Property
Public Property Get CustomerName() As String

Keep this public property accessor with its complementary accessor and the fields or controls it uses.

Controls/CustomerCard.bas · CustomerName
Public Property Get CustomerName() As String
    CustomerName = txtName.Text
End Property
Public Property Let CustomerName(ByVal value As String)

Keep this public property accessor with its complementary accessor and the fields or controls it uses.

Controls/CustomerCard.bas · CustomerName
Public Property Let CustomerName(ByVal value As String)
    txtName.Text = value
End Property
Private Sub cmdOpen_Click()

Enter the complete action, including its input checks and calls to helper procedures.

Controls/CustomerCard.bas · cmdOpen_Click
Private Sub cmdOpen_Click()
    RaiseEvent OpenRequested
End Sub
Private Sub txtId_Change()

Read the current value or selection and update its dependent interface. The binding above determines which object calls this handler.

Controls/CustomerCard.bas · txtId_Change
Private Sub txtId_Change()
End Sub
Private Sub txtName_Change()

Read the current value or selection and update its dependent interface. The binding above determines which object calls this handler.

Controls/CustomerCard.bas · txtName_Change
Private Sub txtName_Change()
End Sub
Copy the complete Controls/CustomerCard.bas file

Replace the file once; do not append duplicate procedures.

Controls/CustomerCard.bas
Option Explicit

Public Event OpenRequested()

Public Property Get CustomerId() As String
    CustomerId = txtId.Text
End Property

Public Property Let CustomerId(ByVal value As String)
    txtId.Text = value
End Property

Public Property Get CustomerName() As String
    CustomerName = txtName.Text
End Property

Public Property Let CustomerName(ByVal value As String)
    txtName.Text = value
End Property

Private Sub cmdOpen_Click()
    RaiseEvent OpenRequested
End Sub

Private Sub txtId_Change()
End Sub

Private Sub txtName_Change()
End Sub

Controls/CustomerBadge.bas

Enter these declarations at file scope, before the procedures.

Controls/CustomerBadge.bas · declarations
Option Explicit

Public Event Tapped()
Public Property Get BadgeText() As String

Keep this public property accessor with its complementary accessor and the fields or controls it uses.

Controls/CustomerBadge.bas · BadgeText
Public Property Get BadgeText() As String
    BadgeText = txtBadge.Text
End Property
Public Property Let BadgeText(ByVal value As String)

Keep this public property accessor with its complementary accessor and the fields or controls it uses.

Controls/CustomerBadge.bas · BadgeText
Public Property Let BadgeText(ByVal value As String)
    txtBadge.Text = value
End Property
Private Sub cmdTap_Click()

Enter the complete action, including its input checks and calls to helper procedures.

Controls/CustomerBadge.bas · cmdTap_Click
Private Sub cmdTap_Click()
    RaiseEvent Tapped
End Sub
Private Sub txtBadge_Change()

Read the current value or selection and update its dependent interface. The binding above determines which object calls this handler.

Controls/CustomerBadge.bas · txtBadge_Change
Private Sub txtBadge_Change()
End Sub
Copy the complete Controls/CustomerBadge.bas file

Replace the file once; do not append duplicate procedures.

Controls/CustomerBadge.bas
Option Explicit

Public Event Tapped()

Public Property Get BadgeText() As String
    BadgeText = txtBadge.Text
End Property

Public Property Let BadgeText(ByVal value As String)
    txtBadge.Text = value
End Property

Private Sub cmdTap_Click()
    RaiseEvent Tapped
End Sub

Private Sub txtBadge_Change()
End Sub

Step 5Keep resources and storage reproducible#

Keep the following files at their declared relative paths. Apply migrations before the first query. Media and report resources must travel with the build.

FilePurpose
licenses/LICENSE.txtBundled asset / license

Step 6Check, run and test the result#

Save all files and run Check. Resolve diagnostics before Run. Developer CLI users can work from the extracted folder:

Developer CLI
mcbasic check CustomerCard.mcproj
mcbasic package build CustomerCard.mcproj --rid osx-arm64

Acceptance checklist

  • Check the UserControlLibrary project.
  • Inspect both property Get/Let pairs and the OpenRequested event.
  • Build its package, then follow the consumer lesson to test it in an application.

Step 7Make one change and repeat the tests#

Add a read-only summary property while preserving the existing public members.

Save a working Git checkpoint first. Change one behavior, Check again and repeat the acceptance checklist. Compare with the downloaded solution if a regression appears.

Source baseline 20f4bfed6b · Build manifest