App vs App

App Battles ! Winner takes all. Last man standing and all that !

No – nothing quite so fun (although it can be a lot of fun)

This has to do with the App class at design time vs the App METHOD (yes it’s a method) at runtime.

The app class at design time can be renamed however you want. You could call it “MyApp”. And for most things that would have no impact. But, you’ll note I don’t say for ALL things.

If you start a new Desktop Application and rename the App class to MyApp I can demonstrate where there are differences.

In the new app’s Window1. Open event lets just do something simple like

dim s as string = App.<press tab>

What you should notice is that none of the defined constants autocomplete. The methods and properties of any Application will show. But no defined constants.

This makes sense because the constants do not exist on Application but they do exist on MyApp.

If we add a few properties to MyApp they also won’t autocomplete. Again the App METHOD, at runtime, returns an Application (or Console Application, Service Application, WebApplication or iosApplication depending on the project type)

Again none of the instances that the App method returns define any of the properties we added to our custom Application instance. And so they will not autocomplete.

What’s an App to do ?

We can definitely deal with this.

One way is to not rename the App class in your project – although this wont alleviate all issues. It will just ignore some for a while. And that is, for many uses, OK.

Or we could cast the return value of the App method to be our defined class type with code like

dim s as string = MyApp(App).<press tab>

This is ALMOST always safe – except in the handful of spots that App can actually be NIL – yay !

It may be better to write something like

dim s as string
if App isa MyApp then
  s = MyApp(App).<press tab>
end if

so a nil return from App won’t matter

Either way the confusion comes from the App METHOD and the App class in your project having the same name. This can make it very unclear whats wrong. And then, when you REALLY need to know why this is, if you’ve ignored this until now you wont know why this weirdness exists.

Unless of course you read this post πŸ˜›

Implementing the Factory pattern in Xojo

When using the “factory” pattern you should only be able to get a valid instance from the factory and NO other way. Thats kind of the point of the pattern – to reduce the number of points at which instances can be created. Normally in Xojo you might have a module with a method that can create instances, and its the only one allowed to do this. The constructors for the classes the factory method can create should be protected or private so they cannot be directly invoked using New outside the module.

Usually it might look something like (note this code will not compile)

Module People

  Public Interface IPerson
      Public Function GetName() as string
  End Interface

  Public Class Villager
    Implements IPerson
      Public Function GetName() as string
        return "Village Person"
      End Function

      Protected Sub Constructor()
      End Sub
  End Class

  Public Class CityPerson 
    Implements IPerson
      
      Public Function GetName() as string
        return "City Person";
      End Function

      Protected Sub Constructor()
      End Sub
  End Class

  Public Enum PersonType
    Rural
    Urban
  End Enum

  Public Function GetPerson(type as PersonType) as IPerson
  
    select case type
    case PersonType.Rural
      return new Villager()
    case PersonType.Urban
      return new CityPerson()
    else
        raise new UnsupportedOperationException
    end select
  End Function

End Module

An alternative would be to not use an Interface for IPerson but to make it a base class – they end result is similar.

But, you cant do either in Xojo. At least not quite like my code above shows.

If you have a factory method in the module it cannot invoke their constructors. They are only callable by items in the class hierarchy. It has no special means to access the private or protected constructors of the classes it contains.

So you cant easily restrict construction to ONLY the factory method since what you really need is a “module” or “namespace” scope. And that doesn’t exist.

What you need to do is create an INTERFACE for the various classes in the namespace you intend to expose and make the classes in your namespace implement these interfaces. In addition you need to make the interfaces PUBLIC so they can be used outside the module. As well you need to make the classes that implement the interfaces PRIVATE so you can’t actually try and instantiate them outside the module. This has the unfortunate side effect of making it so you can only use the classes in the module via their interfaces. Remember what we really wanted was just to make it so the only legal way to get an instance was to use the factory.

Note that by having to do everything via an interface this means that “properties” are exposed by pairs of getter / setter methods. Fortunately in Xojo this has little semantic impact except that you have to write the code for it.

All code not in the module must use the interfaces as that’s all you have available.

But now because the classes in the module are PRIVATE you can put as many public constructors on them as you desire. They won’t be callable by anything outside of the module so instances cannot be created in ANY way except by calling the factory method in the module.

Module scope would help reduce this work needed to implement the Factory Pattern by making it possible to implement the module’s classes with “module” scoped constructors. This way you could have the factory return any of the parent or subclass instances and you could skip all the interfaces.

A sample of the initial implementation that doesnt work and the fixed version is here

C Unions

An interesting question came up on the forums the other day about how to mimic “Unions” from C.

Turns out I had answered this some time ago – its close but not exactly the same as in C. But it is close enough to be functional and close enough for most uses.

And it’s not mentioned anywhere in the Xojo docs. Not even in advanced topics.

The requirement was a need to be able to interpret a set of data (4 bytes in the forums post case) in one of two different ways. One was as 4 separate byte values, and the other as 2 16 bit values.

In the example I had given previously the need was a common “record” type that had an identifying “record type” byte as the first byte and several other interpretations of the data that followed. In all cases the records were the same total size but their contents varied.

In the example I have the three structures following :

Structure Structure1
  switchCode as uint8 
  rest(4) as uint8
End Structure

Structure Structure2
  switchCode as  uint8
  val1 as uint16
  val2 as uint16
End Structure

Structure Structure3
  switchCode as uint8 
  val1 as uint32
End Structure

Note that each has, in this set up, a byte at the beginning that is at a common offset and that is used to determine which of the three structures is the correct one to be using to interpret the data. In some cases there may be some other indicator or mechanism to know which way to interpret the data.

In this example all structures are defined to be the same total size. This is NOT required. A C union will be the largest of any of the defined union members. So make sure you account for this when you decide what memoryblock size to use for the initial data buffer.

The data buffer is just a memoryblock of whatever size is needed. To interpret the data differently a Ptr is used. And since Ptr’s can interpret the data they point at via a structure we can, once the mb is assigned to the Ptr, now interpret the data using any of our defined structures.

Dim mb As new MemoryBlock(5)

mb.Byte(0) = &h20
mb.UInt16Value(1) = 32
mb.UInt16Value(3) = 254

Dim p As ptr = mb

Dim s1 As structure1 =  p.structure1 // makes it so I can read the
            // data in mb using the fields from structure1
            // but I could use any of the three OR 
            // some other mechanism to figure out which structure
            // to use to inspect the data

Select Case s1.switchcode

Case &h20
  Dim s2 As structure2 =  p.structure2 
// makes it so I can read the data in mb using 
// the fields from structure2

  Dim value1 As UInt16 = s2.val1
  Dim value2 As UInt16 = s2.val2
  Break

Case &h21
  Dim s3 As structure3 =  p.structure3 
// makes it so I can read the data in mb using 
// the fields from structure3

  Dim value1 As UInt32 = s3.val1
  Break

Case &h22  
  Dim struct1 As structure1 =  p.structure1 
// makes it so I can read the data in mb using 
// the fields from structure1

  Dim value1 As UInt8 = struct1.rest(0)
  Dim value2 As UInt8 = struct1.rest(1)
  Dim value3 As UInt8 = struct1.rest(2)
  Dim value4 As UInt8 = struct1.rest(3)

  Break

End Select

Using this technique we can “overlay” the structure onto the raw data in the memoryblock and read it out using the structures fields.
Very handy especially for those cases where you need to read from file formats, memory formats that involve C unions.

About Attributes

A recent feedback case made me think that there may be a real lack of information about attributes.

A lot of people believe that attributes are key value pairs that must have a valid identifier as the NAME and ALWAYS have a quoted string for a value.

This is incorrect.

Attribute name can be quoted strings – meaning you can, by using a quoted string for the name – have names that include spaces that would normally be invalid.

Secondly you CAN have an attribute VALUE that is NOT a quoted string. When you do this the value that you will see at runtime comes from a CONSTANT with the name placed in the value.

An example is here

Coding style

Thomas Templemann wrote a nice blog post about his preferred coding style guidelines.

And most I absolutely agree with.

Except one.

His suggested style is to test booleans simply for the value they hold and not to test for TRUE or FALSE explicitly. He considers testing for TRUE or FALSE bad style. Examples of bad style are :

if hidden = true then ... // bad style
end if
if hidden = false then ... // bad style
end if

Instead he suggests using good names and the following style

if isHidden then ... // good style
end if
if not isHidden then ... // good style
end if

Personally I find that sometimes picking a “good name” so things read like an English sentence can be challenging and that any code you get from someone else may not adhere to the “good name” principle.

As of late I’ve been working in a lot of code written in German. All the variable names, controls, etc are German. And so nothing reads well to me since I don’t read German.

So I prefer a style like

if einigeWirklichSchrecklicheVariablennamen = true then ... 
end if
if aθΏ™ε„Ώζ²‘ζœ‰ε‘εΈƒε‚ζ•°ε’ŒθΏ”ε›žε€Ό = false then ... 
end if

All this said whatever style you use stick to it and use it consistently throughout your code. Use Thomas’s if you like them and they work for use. Or those from BKeeney. Or write your own set, try them out and work with them and tweak them until they make code easier to write AND easier to read and comprehend when you’ve been away from it for months at a time.

Named parameters

Currently when you call a method in Xojo the parameters are matched up starting from the first to the last from left to right. They are matched up based on their position in the argument list.

One thing some other languages support is “named parameters”.

What this allows is a certain degree of flexibility that doesn’t exist with positional parameters like Xojo uses.

For instance in Xojo if you have a method, Foo, with parameters as follows

Sub Foo(a as integer, b as string, c as Date)

you can call it only using the correct types of parameters in the correct order like

Foo(123, "345", new Date)

There are ways, with optional parameters, to modify this normal operations. If that method was defined as

Sub Foo(a as integer = -1, b as string = "", c as Date = nil)

You could call this like

Foo()
Foo(123)
Foo(123, "345")
Foo(123, "345", new Date)

All the parameters are optional and any that are not supplied a default value as shown in the declaration. But everything is still positional. And there are things you cannot do like skip one parameter. None of these will compile.


Foo(, ,New Date)
Foo( , "345" ,New Date)
Foo(123, ,New Date)

So how would named parameters help ? Named parameters can let you say, explicitly, “this value is for this parameter” rather than just matching up by position. For instance out call to Foo might look like

Foo()
Foo( a:123)
Foo( a:123, b:"345")
Foo( a:123, b:"345", c:new Date)

And you might also be able to do something like

Foo( b:"345", a:123 )
Foo( a:123, c:new Date, b:"345")

And not have to worry about the order. And this might let you do something like

Foo(c:New Date)
Foo( b:"345" , c:New Date)
Foo(a:123, c:New Date)

which skips certain parameters in a manner that you cannot do today.

Certainly this would not be a trivial change to Xojo to support positional and/or named parameters. But there are languages that do this.

In the mean time its possible to manually create your own support for “named parameters”.

If we create Foo with two signatures like

Sub Foo(a as integer = -1, b as string = "", c as Date = nil)
End Sub
Sub Foo(paramarray values as Pair)
End Sub

Then Foo could be called as

Foo(123, "345")
Foo(123, "345", New Date)
Foo( "c":New Date)
Foo( "b":"345" , "c":New Date)
Foo( "a":123, "c":New Date)

NOTE that the “names” of the parameters have to be a literal type – in this case a string.

In this set up though we cant use no parameters. So let’s alter the set up to have at least one parameter otherwise the compiler will have an ambiguous overload in the case there are no parameters. It couldn’t distinguish between the call to Foo where it should use all default parameters and an empty paramarray. So now our declarations look like

Sub Foo(a as integer = -1, b as string = "", c as Date = nil)
End Sub
Sub Foo(value as pair, paramarray values as Pair)
End Sub

And we’ll be able to call this like

// these are positional
Foo
Foo(123)
Foo(123, "345")
Foo(123, "345", New Date)

// the use "named" parameters
Foo( "c":New Date)
Foo( "b":"345" , "c":New Date)
Foo( "a":123, "c":New Date)

So we’re on our way to being able to use either positional parameters OR named parameters. Now how do we make use of the overload that supports named parameters to call the one that supports positional parameters ?

In this method we need to

  • make sure we declare one local variable of the same type for each positional parameter
  • make sure we set these local variables default value to the same default values as the version that uses positional parameters
  • process the FIRST pair and all subsequent pairs in the same fashion and assign values to the local variables

Following all those admonitions the code in the version of foo using named parameters looks like

Dim a As Integer = -1
Dim b As String 
Dim c As Date

Select Case value.Left
Case "a"
  a = value.Right.IntegerValue
Case "b"
  b = value.Right.StringValue
Case "c"
  c = value.Right
End Select

For i As Integer = 0 To values.ubound
  
  Select Case values(i).Left
  Case "a"
    a =  values(i).Right.IntegerValue
  Case "b"
    b =  values(i).Right.StringValue
  Case "c"
    c =  values(i).Right
  End Select
  
Next

foo(a, b, c)

There are caveats to this technique though. Positional parameters will be checked by the compiler for type, the “named parameter” version will only be checked that the passed items ARE pairs. The names and values contained by those pairs are variants and so can be anything. And you can pass the same named parameter multiple times since the compiler is unaware of named parameters. And you can’t use “byref” parameters with the named parameter version – you COULD use reference types though.

I’d love to see Xojo support named and positional parameters using a syntax that looks like “pairs” as first presented.

In the mean time this is what we have.

Simple code sharing on macOS

For anyone not using version control perhaps the easiest way to share code between various projects is to use external items. However, not everything cam be made external. Modules that contain classes & other modules cant be shared via external items.

So how can you share these ?

On macOS the answer is … ALIASES !!!!!

The trick is how you set things up when you want to share such a thing between various projects. But this only works for TEXT projects because text projects save everything in separate files. For binary & XML projects you really dont have much in the way of choices when it comes to sharing Modules with other classes & modules in them.

And, if you ARE using TEXT projects then its also very likely you ARE using version control. So this tip is really for a very narrow set of use cases.

Basically what we need to do is set up an aliases that refers to the code we want to share instead of the code in our project.

Lets walk through a really simple example.

First create a new folder on your desktop – I called mine Code Sharing Example.

Now lets create a new project and add a module that we’re going to share between this new project and others.

And we’ll save this in a new folder we create inside the new folder we created earlier. I named the folder this is saved in Originator since we’re going to have the original source in this project and others will use it.Make sure you save the project as a TEXT, or Xojo Project. I also named the project Originator.xojo_project

This forms the basis of what we want to share.

Start a new desktop project. In this example I happen to use a desktop project but it could be a web or console app. iOS is harder to do this with because it uses the new, now deprecated Xojo framework so data type compatibility may be an issue. However, if you are using the new framework in desktop or other apps then you can use the same technique.

In this new app we are going to add a PROXY module that we will fix up manually later. Its just a placeholder. But it does make life simpler if you name this the same as the one we wanted to bring in from the other project. So we’ll name it ToBeShared like in the Originator project.

Now save this project in a new folder inside the Code Sharing Folder. I named mine Second Project and the project also named Second Project.

And now the manual work to make it so we can share the module.

A module, when saved as a text project, is a file. If you look in the folder that holds the Originator Project you will see a file named ToBeShared.xojo_code as well as a directory named ToBeShared.

In order to get Second Project to read the Originator Projects module and contained classes we need to replace the Second Projects file on disk with an alias named exactly the same – extension and everything. And we also need to make sure we have an alias to the directory with the ToBeShared name so the IDE realizes that this is a module with contents.

Since we added the proxy in the Second Project with the exact name we do not need to do anything to the project manifest.

First navigate to Second Project and remove ToBeShared.xojo_code

Then navigate to Originator Project and select ToBeShared.xojo_code and the ToBeShared directory. And press Cmd + Ctrl + A (or right click and select make alias)

Move these two aliases to the Second Project directory.

We’re almost done.

Navigate to Second Project.

Change ToBeShared alias so its names is only ToBeShared without the alias as part of the name. And ToBeShared.xojo_code alias to ToBeShared.xojo_code again with the alias part removed.

Open the Originator project & add a method to the Shareable class and the ToBeShared module. Save.

Now open the Second Project and you should see those just added items.

And here is where norm realizes he missed a step πŸ˜›

Thats ok though.

I’ll show you how I fixed it and what I messed up earlier.

To explain the problem. We should have added not just a proxy that we’d fix for the module but the Shareable class inside it as well. This would have made it so we did not need to manually fix the manifest and creating the aliases would have been sufficient. If you were to go back to that step & add the class then everything would just work now.

But since I missed that step I’ll manually fix the manifest. If you opened the Second project what was missing is the class that we added inside the ToBeSharedModule. The reason is that the manifest does not know there is such a class.

In the Originator project you would see something like

Module=ToBeShared;ToBeShared.xojo_code;&h000000000F00AFFF;&h0000000000000000;false
Class=ShareableClass;ToBeShared/ShareableClass.xojo_code;&h00000000580AC7FF;&h000000000F00AFFF;false

But when you open the Second Project manifest, because we did not add the class to the module, you only see something like

Module=ToBeShared;ToBeShared.xojo_code;&h0000000042EA77FF;&h0000000000000000;false

and no entry for the class. And thats the problem. The manifest lists everything a project is composed of and since there is no entry for the class the class contained by the module doesnt show. And the fix is simply to copy the lines for the module & class in the manifest from the Originator project and replace the one line for the module in the Second Project.*

And once you copy that across & save the manifest and reopen the project there’s the code from the Originator project. And if you make chnages to this code in the second project and reopen the originator project the changes will exist there as well.

One thing to take care with – do NOT open both projects at the same time and edit in both. You are sure to cause yourself problems.

If you add new classes to either Originator or Second Project you will have to do many of the same manifest file changes over again so each project knows about the added items.

*When manually editing a manifest there are some things to be careful about. One is the two hexadecimal entries on the line. The first is the items id and the second the id of the item that contains this one. These items need to be unique within a project. Take care to make sure this is true otherwise you run the very real risk of messing your project manifest up to the point your project won’t load.

Code for safety II

Back when I wrote Code for Safety I gave one example of something that I’m sure we’ve all done from time to time. Saving the state of some flag and then returning and having possibly multiple places to reset the flag we saved.

There’s another thats is more common with the advent of HiDPI support for Windows; drawing in a listbox event like CellBackGroundPaint Saving the graphics state, disabling antialiasing, and then needing to restore that state.

This is especially true on Windows where you may need to disable anti-aliasing, change the foreground color & fill the background to achieve some custom effect. If you dont disable anti-aliasing you can end up with odd effects as noted in the documentation and this post.

Having a way to save the existing state and consisntenly and reliably restore it to what it was when the method was called is useful since you dont know if the graphics object is passed on to other events like CellTextPaint. Not restoring the state may lead to unwanted side effects.

So how to make it so you can simply save the state and never worry about it being restored properly ? As I mentioned before ; a class that has almost nothing to it but a constructor & a destructor.

My implementation is called GraphicsStatePreserver.

The constructor is simply

Sub Constructor(g as graphics)
  mG = g
  
  Me.mAntiAlias = g.AntiAlias
  Me.mAntiAliasMode = g.AntiAliasMode
  Me.mBold = g.Bold
  Me.mCharacterSpacing = g.CharacterSpacing
  Me.mForeColor = g.ForeColor
  Me.mItalic = g.Italic
  Me.mLastPage = g.LastPage
  Me.mPenHeight = g.PenHeight
  Me.mPenWidth = g.PenWidth
  Me.mScaleX = g.ScaleX
  Me.mScaleY = g.ScaleY
  Me.mTextFont = g.TextFont
  Me.mTextSize = g.TextSize
  me.mtextunit = g.TextUnit
  Me.mTransparency = g.Transparency
  Me.mUnderline = g.Underline
  
End Sub

We save the current state of the various writeable properties of the graphics into locals, and a hard reference to the graphics object. We keep a hard reference to make sur it cannot go out of scope before we have done our thing to restore the various settings.

The destructor is equally simple

Sub Destructor()
  mg.AntiAlias = Me.mAntiAlias 
  mg.AntiAliasMode = Me.mAntiAliasMode 
  mg.Bold = Me.mBold 
  mg.CharacterSpacing = Me.mCharacterSpacing 
  mg.ForeColor = Me.mForeColor 
  mg.Italic = Me.mItalic 
  mg.PenHeight = Me.mPenHeight 
  mg.PenWidth = Me.mPenWidth 
  mg.ScaleX = Me.mScaleX 
  mg.ScaleY = Me.mScaleY 
  mg.TextFont = Me.mTextFont 
  mg.TextSize = Me.mTextSize 
  mg.textunit = Me.mTextUnit
  mg.Transparency = Me.mTransparency 
  mg.Underline = Me.mUnderline 
  
End Sub

When this class is destroyed it will put back all the properties on the graphics just as they were when the instance was created.

And since an instance is used like

Dim statepreserver As New GraphicsStatePreserver(g)

#If targetwindows
  g.AntiAlias = False
#EndIf

If row < 0 Then 
  Return True
End If
If column < 0 Then 
  Return True
End If

// whatever othe r code you need in cell background paint

Return True

This instance will ONLY go out of scope, and be destroyed, at the points where the event is being exited. And that happens to be the exact points we want to restore the graphics state.

Here’s the entire implementation

Class GraphicsStatePreserver
	Sub Constructor(g as graphics)
	  mG = g
  
	  Me.mAntiAlias = g.AntiAlias
	  Me.mAntiAliasMode = g.AntiAliasMode
	  Me.mBold = g.Bold
	  Me.mCharacterSpacing = g.CharacterSpacing
	  Me.mForeColor = g.ForeColor
	  Me.mItalic = g.Italic
	  Me.mLastPage = g.LastPage
	  Me.mPenHeight = g.PenHeight
	  Me.mPenWidth = g.PenWidth
	  Me.mScaleX = g.ScaleX
	  Me.mScaleY = g.ScaleY
	  Me.mTextFont = g.TextFont
	  Me.mTextSize = g.TextSize
	  me.mtextunit = g.TextUnit
	  Me.mTransparency = g.Transparency
	  Me.mUnderline = g.Underline
  
	End Sub

	Sub Destructor()
	  mg.AntiAlias = Me.mAntiAlias 
	  mg.AntiAliasMode = Me.mAntiAliasMode 
	  mg.Bold = Me.mBold 
	  mg.CharacterSpacing = Me.mCharacterSpacing 
	  mg.ForeColor = Me.mForeColor 
	  mg.Italic = Me.mItalic 
	  mg.PenHeight = Me.mPenHeight 
	  mg.PenWidth = Me.mPenWidth 
	  mg.ScaleX = Me.mScaleX 
	  mg.ScaleY = Me.mScaleY 
	  mg.TextFont = Me.mTextFont 
	  mg.TextSize = Me.mTextSize 
	  mg.textunit = Me.mTextUnit
	  mg.Transparency = Me.mTransparency 
	  mg.Underline = Me.mUnderline 
  
	End Sub

	Private Property mAntiAlias As boolean
	Private Property mAntiAliasMode As Graphics.AntiAliasModes
	Private Property mBold As boolean
	Private Property mCharacterSpacing As Integer
	Private Property mForeColor As color
	Private Property mG As graphics
	Private Property mItalic As boolean
	Private Property mLastPage As Integer
	Private Property mPenHeight As double
	Private Property mPenWidth As double
	Private Property mScaleX As double
	Private Property mScaleY As double
	Private Property mTextFont As string
	Private Property mTextSize As Single
	Private Property mtextunit As FontUnits
	Private Property mTransparency As double
	Private Property mUnderline As boolean

End Class

How do you raiseevent ?

When you create a custom control from a canvas, container control or some other base class its not unusual to use raise event to create new events like “BeforeButtonPressed”, “AfterButtonPressed” or to just make it so you;r control can implement normal events like Open, Close, etc and pass then along.

You’ll see code using raiseevent to cause these events to be raised on any instances.

But, you can use raiseevent for much more than this and use it in places you might not expect.

For instance, you might want an event to return a boolean as well as some parameter byref much like the SelectColor method does.

Dim c As Color

If SelectColor(c) Then
  // use the color selected
Else
  // c is still "default"
End If

This isnt so bad and it easy to imagine writing the SelectColor method to do exactly this. But what if SelectColor is an event in a custom control you’re writing ? You might be tempted to write

Dim c As Color

Dim b As Boolean = SelectColor(c)

If b Then
  // use the color selected
Else
  // c is still "default"
End If

But in a way this hides the fact that SelectColor IS an event your code is calling for an instance to implement. Believe it or not you CAN write

Dim c As Color

Dim b As Boolean = RaiseEvent SelectColor(c)

If b Then
  // use the color selected
Else
  // c is still "default"
End If

And this then is more obvious that SelectColor IS an event that an instance might have implemented. But, since you can write that why not

Dim c As Color = &cffffff

If RaiseEvent SelectColor(c) Then
  // use the color selected
Else
  // c is still "default"
End If

And once again this works just as we expect. And it helps make your code clearer that you ARE calling an event that an instance may have implemented. And, code clarity is a good thing.

I think if you try you might be surprised at the spots where putting RaiseEvent works exactly as expected and helps improve code clarity.

Dynamic menu handling

A lot of times when you need to create a menu at runtime you don’t know the number of items and those items may require some additional data to be handled correctly like a folder item, window reference etc. And in cases like this a subclass of MenuItem makes sense so you can add properties to the subclass and implement the action event to handle that extra data. This is a common pattern for things like the Window menu, Font menu and Recent items.

But its not the only way to handle a dynamic menu.

Suppose you want to add a menu at runtime that is well known before hand and depending on which user is using your application the menu has different entries ?

In such a case you can define everything ahead of time and it will all behave just like if you had defined it in the IDE menu editor.

The trick is to know that the “AutoEnable” setting for menus is dependent on the NAME of the menu item, not the text it contains.

Lets see how we can take advantage of this fact.

Create a new desktop application. In Window1’s open event we’re going to add a menu, and some items to that menu.

Add the following code to the Open event


Dim SelfMenu As New MenuItem("Self Service")
Self.MenuBar.Append SelfMenu
SelfMenu.Enabled = True

Dim fMenu As MenuItem

fMenu = New MenuItem("selfchgpswd")
fMenu.Name = "selfchgpswd"
fMenu.Text = "Change Password"
fMenu.AutoEnable = True
SelfMenu.Append(fMenu)

Note that we have set the name. THIS is crucial. And each item added should have a unique name otherwise you can end up with odd problems.

If you run at this point you should see the menu is added but the items are not enabled. But note that we DID set the AutoEnable property. The Xojo runtime will automatically enable this item IF there is a handler for it on our Window.

So lets add a menu handler for selfchgpswd (menu handlers use the NAME to match the menu item with the menu handler to be enabled & executed)

Right click on Window1 in the navigator and select “Add to Window1” and add a menu handler. In the editor field for the menu handler name put in selfchgpswd. You CAN define a menu handler for menu items that do not exist.

In the menu handler simply add

break

And now run.

First you will see that the menu is added AND the item is now enabled ! And if you select that item from the menu you should stop at the break statement – the Code in the menu handler IS being called exactly as we expected.

At the end of the day this gives you a second way to handle menu items that you add and remove at runtime and, in this case, you know beforehand and can add the code just like you would have if you had defined the menu in the Menu editor.

Enjoy !