Class Properties, Methods and Events
From Xojo Documentation
This topic covers properties, methods and events that you can add to classes.
A Property is a trait that tells you something about an object. You use them as a way for class instances to store or calculate values. You can add four types of properties to classes: properties, computed properties, shared properties and shared computed properties.
You can add properties to a subclass to store values that its super class doesn’t store. For example, you might want to create a subclass of the TextField control that stores the last value the user entered. This would allow you to selectively reject the current entry and restore the last entry.
Learn more about Properties and Computed properties in the Properties topic.
Properties are variables that belong to an entire class instance rather than just a single method. To add a property to a class, use the Add button on the Code Editor toolbar, Insert ↠ Property from the menu, the contextual menu or the keyboard shortcut (Option-Command-P on macOS or Ctrl+Shift+P on Windows and Linux). You can set the property name, type, default value and scope using the Inspector.
To quickly create a property, you can enter both its name and type on one line in the Name field like this: PropertyName As DataType. When you leave the field, the type will be set in the Type field.
Properties added in this manner are sometimes called Instance Properties because they can only be used with an instance of the class. You can also add computed properties to a class. These are properties whose values are calculated rather than stored.
A shared property (sometimes called a Class Property) is like a "regular" property, except it belongs to the class, not an instance of the class. A shared property can be accessed from anywhere its scope allows. In many ways, a public shared property works like a protected module property.
It is important to understand that if you change the value of a shared property, the change is available to every usage of the shared property. Generally speaking, shared properties are an advanced feature that you only need in special cases. For example, if you are using an instance of a class to keep track of items (e.g., persons, merchandise, sales transactions, and so forth) you can use a shared property as a counter. Each time you create or destroy an instance of the class, you can increment the value of the shared property in its constructor and decrement it in its destructor. (For information about constructors and destructors, see the section Constructors and Destructors.) When you access it, it gives you the current number of instances of the class.
Shared Computed Properties work exactly like you expect. They are shared versions of computed properties.
Methods provide functionality for your classes. They usually perform some action, such as loading data or calculating values.
Learn more about Methods in the Methods topic.
Methods (Instance Methods) are methods that belong to a class instance.
Shared Methods (also called class methods) are methods that belong to the class rather than an instance. A shared method is like a "regular" method, except it belongs to the class, not an instance of the class. A shared method can be accessed from anywhere its scope allows. In many ways, a public shared method is equivalent to a protected module method.
Generally speaking, shared methods are an advanced feature that you only need in special cases. For example, one use of a shared method is for the Factory pattern.
Scope of Items
Items on a class, such as method or properties must have a scope defined. The scope indicates where the property can be used. You set the Scope using the Inspector for the item. There are three choices:
- Public: Can be used anywhere in your code with no restrictions, either within the class or from any class instance. To access the item within the class, simply refer to it by its name. For example, to use a property or method in a class instance, use dot notation:
- Protected: Can be used by the class in which it is contained and any subclasses. To access the item, refer to it by its name.
- Private: Can be used only by the class in which it is contained. To access the item, refer to it by its name.
Refer to Encapsulation for more on scope.
Events are a type of method that is called by some action (or event) that has occurred. These events have nothing to do with the “events” in “event-driven programming”. Many classes and controls have their own built-in events (which are covered in the User Interface and Framework books), but you can also create your own events using Event Definitions.
You do not directly call event handlers in your own code. For example, if you find that you need to manually call the Action event of a button, then you should instead put the code you need to call in a method. You can have the Action event handler call the method and you can now call the method directly in your own code as needed.
Event Definitions gives you a way to add your own Event Handlers to subclasses. Event Definitions can be called only from the class itself, but they can be implemented as an Event Handler only by its subclasses. To add an event definition to a class, use the Add button on the Code Editor toolbar, Insert ↠ Event Definition from the menu or the contextual menu. With an event definition in place, you can then implement the event using Add Event Handler on a subclass or when you add this class to a layout.
For example, say you have a Save method on a class and decide that you should give subclasses a way to do processing before and after the save. One way you could do this is by overriding the Save method on the subclass like this:
This works but it relies on you defining and implementing everything properly. If you forget to call Super.Save then your overridden method won't actually save! But if you do this with events, then there is no room for error. With events, you create two event definitions on the super class: PreSave and PostSave. In the Save method on the super class, you then call PreSave at the beginning and PostSave at the end. When you create a subclass, you will see that it has two Event Handlers you can add to it: PreSave and PostSave. Simply add those event handlers and implement them as needed. Since you are not overridden the Save method, your code circumvents the possible issue shown above.
The built-in control classes all contain a wide variety of event handlers (such as Opening), all of which work in this manner.
Note that when you implement an event handler, it no longer appears in subclasses. If you want the event handler to still be available to additional subclasses, you need to create a new event definition in the subclass (matching the name and parameters) and then call it in from event handler you implemented. You can easily add a matching event definition by right-clicking on the event you have implemented and choosing "Create Event Definition from Event".
When you create an event definition, you can enter a description for it in the Description field on the Advanced (gear) tab of the Inspector. This description appears in the Add Event Handler window when the event is selected.
Looking back at the Animal example that was done using Inheritance with method overriding, this is how you would do it using events.
Create a new class called Animal. Add to it a Speak method that returns String with this code:
Now add to the Animal class an Event Definition called SpeakSound and set its return value to String.
Next, create a subclass of Animal, called Cat. Click on the button “+” button on the toolbar and select “Add Event Handler”. In the dialog, you will see the SpeakSound event handler. Select and and press OK. The code for this event handler is:
Create another subclass of Animal, called Dog, and also add the SpeakSound event handler with this code:
To test this, create a button on a window. In the Action event of the button add code to create an array of Animals:
For Each a As Animal In animals
When you run this code, you will see “Meow!” and then “Woof!”.
Because Cat and Dog are both subclasses of Animal, they are allowed to be assigned to a variable (the animals array) with a type of Animal.When you call the Speak method of Animal (in the loop), it in turn calls the SpeakSound event handler of each subclass that was added to the array.
The AddHandler command is used to have a method on one object handle the processing of an event on another. This is often used to allow you to instantiate a class directly and implement its event without having to create a separate subclass.
For example, if you want to implement the Run event of a Timer, you will typically create a subclass. This can be done by dragging a Timer onto your window or web page or by adding a Timer subclass to your project and using that instead.
Alternatively, you can declare the Timer in your code and then use AddHandler to have the Action event handled by a method on your window. For example:
AddHandler t.Run, AddressOf MyTimerMethod
t.RunMode = Timer.RunModes.Multiple
t.Period = 500
t.Enabled = True
In order for this to work, you must have a method in the window called MyTimerMethod and it must have a parameter for the timer itself:
If the event you are handling has additional parameters, include them after the initial parameter used for the class itself. AddHandler can also be used in this manner for Threads: