You’re welcome !

Some one at Xojo could have, should have, posted about how to do this

It didnt seem to be forthcoming so I did over on INN

Just disappointed that Xojo seems to just not try & help users unless its via email

😞

Adding Event handlers

OK So now we have a control on a Window
But how do we react to events that happen to that control ?
Like KeyDown, Keyup, GotFocus, LostFocus, and TextChanged. Thats all the events there are on TextFields – for now.

In Xojo you’d just add the event handler to the control & put code in it.
In C# its much the same. In C# we write an event handler and attach the handler to the controls event.

But hat events are there ? We can see these in the Assembly Browser.

Right click on TextField and select Go to definition

If we fold open TextField we see the following

You’ll see properties like BackColor, Editable, and events like GotFocus, LostFocus, KeyDown and KeyUp.

If you click on the GotFocus event handler you’ll see it says

using System;

public event EventHandler GotFocus;

This says that GotFocus is an EventHandler that takes NO parameters.
C# defines the EventHandler type. In Xojo terms its a delegate.
And that is a method that matches some specific signature.
In this case you can look at what that signature is – but I’ll save you the trouble.

It looks like

public delegate void EventHandler (object? sender, EventArgs e);

So the method we want to write to handle Got Focus needs to look like the following (the name is totally arbitrary but again good names help)

private void textfield_GotFocus(object sender, EventArgs e)
{
}

But where to put this ?
Believe it or not, even in Xojo, the event handlers for controls are part of the WINDOW.
So we’ll write this event handler and put it in the MainWindow.cs as part of the class.

Now we have a handler. How do we attach it to the control itself ?

If you look closely at the image above its that one line after we created the textfield and put text in the field.

    textfield.GotFocus += textfield_GotFocus;

That line is roughly the equivalent of

    Addhandler textfield.GotFocus, addressof textfield_GotFocus

The handler doesnt DO much – yet – but we’ll fix that.
Lets just make it write to the debug log when we get focus.

In the event handler put

    Debug.Print("textfield_GotFocus");

Now when you run you probably want see anything. But if you click on Application Output you should see the debug messages

Now because there IS only one field on the layout that can get focus we’re not going to see a lot of changes. If you added a second text field and hooked up the SAME got focus handler to it you’d be able to move focus and see a got focus event each time focus shifted.

One thing you’ll notice is that we reused the SAME event handler between the two text fields. More or less you can easily do what Xojo does for control sets (controls arrays)

And in the event handler you can see which control was clicked

using System;
using System.Collections.Generic;
using System.Diagnostics;
using Einhugur.Forms;

namespace getting_started
{
	public class MainWindow : Window
	{
        TextField textfield1;
        TextField textfield2;

        // much like the constructor in Xojo
        protected override void SetupWindow(WindowCreationParameters prm)
        {
            prm.Left = 200;
            prm.Top = 100;
            prm.Width = 600;
            prm.Height = 400;
            prm.Title = "My first window";
            prm.InitialPlacement = WindowPlacement.Center;
        }

        protected override IEnumerable<Control> SetupControls()
        {
            textfield1 = new TextField( 10, 23, 80,  23);
            textfield1.Text = "not edit no select";
            textfield1.GotFocus += textfield_GotFocus;

            textfield2 = new TextField(10, 55, 80, 23);
            textfield2.Text = "not edit no select";
            textfield2.GotFocus += textfield_GotFocus;

            return new Control[] { textfield1, textfield2 };
        }

        private void textfield_GotFocus(object sender, EventArgs e)
        {
            Debug.Print("textfield_GotFocus " + ((TextField)sender == textfield1 ? "textField1" : "textField2") );
        }               
    }
}

Now the output looks like

The project as it stands now

Adding menubar & controls in C#

For all of you following along YEAH its about damned time ! 🙂
I agree

I’ve been proceeding slowly to make it so you can follow and not try to cram 10000 items in one post (we ARE trying to keep it manageable)

First Lets remove the last bits of “cruft” left in our getting starting project
Since we’re not actually using a normal macOS document application we can delete the ViewController.cs and ViewController.designer.cs
Simply right click on ViewController.cs and select delete.

You’ll get a dialog asking if you want to delete the view controller and its “code behind children”

Select Delete and both will be removed. Your should still be able to run your application.

Now on to the fun stuff !

First lets add a menu bar so we have a normal Quit menu Item in it 😛

Start by adding a new class (almost everything in our C# world is an actual class)

We end up with an empty class that we need to edit to set up properly.

We’re using an actual macOS NSMenu here – so we need to add the AppKit using clause so the IDE & compiler know about this in our class. And we’ll make our AppMenu class a subclass of NSMenu

We’ll want to add & retain references to certain menu items – note this doesnt mean you cant handle dynamic menus. Just that there are some, like the Quit menu item, that we dont need to deal with dynamically. So we can add a property to our class to hold this reference when we create it

    public class AppMenu : NSMenu
    {
        public static MenuItem QuitMenuItem;

And we’ll want to alter the Constructor (the method named the same as the class) so it takes one parameter – the menus TITLE

public class AppMenu : NSMenu
{
        public static MenuItem QuitMenuItem;

        public AppMenu(string title) : base(title)
        { }

The AppMenu method is new so requires some explanation. The first portion public AppMenu(string title) is just like any other method you’ve ever seen. It has a scope public, a name AppMenu, and a list of parameters string title. But then there is : base(title) which in C# is shorthand for “call the super class constructor method that takes a string parameter”

So just by declaring the method this way you have created the constructor and call the super class constructor. But so far it doesnt do anything – the empty {} is the give away.

When an app start we need to create the “Application Menu” and add whatever items to it we want. On macOS the OS may add some of its own.

So we’ll create that menu and make it have a Quit item in it.

public AppMenu(string title) : base(title)
{
  // Application top level Menu
  var appMenu = new NSMenuItem(); // create the top item for Application
  appMenu.Submenu = new NSMenu(); // add a sub menu

  QuitMenuItem = new MenuItem("Quit", "q"); // create the QUIT item

  // create and set the ARRAY of items to a NEW ARRAY containing
  // our newly created QuitMenuItem
  appMenu.Submenu.Items = new[]
  {
    QuitMenuItem
  };

  // THIS is like ME or SELF
  // here this means the app menu itself
  this.Items = new[] { appMenu };
}

This will create the menu – but doesnt “attach” it to our application yet. So if you run right now you wont see this code get run.

You can test this by setting a breakpoint in the code. There are several ways to achieve this. By default pressing CMD+\ will toggle a break point on the line containing the insertion point. Or you can click in the break point gutter

When you run you will see that break point is NEVER reached.
So lets fix that.

Open up the AppDelegate.cs

When an applications starts up, just like in Xojo, you will see the constructor get called, followed by the app “Opening”. In this case we’re going to set up the menu, and “menu handlers” in the Opening event (its not really an event in this framework but thats what it would be in Xojo)

So – how to know what the method we need to implement might be named ?
We could guess. That might take a long time.
I could tell you but I might not be around all the time 🙂
Or we can just go look

In AppDelegate right click on “Application” in the line

	public class App : Application

and select “Goto definition”

There s a lot of stuff in here. But what we want so see is which methods are declared PUBLIC VIRTUAL. Why ? thee are ones that are defined to be implemented in a subclass. They are quite literally meant to be overridden.

And there are several of interest to us right now

protected virtual void Opened ()

protected virtual void Opening ()

protected virtual void Closing ()

There are others but these are the ones we care about right now

Opening is called right after the application instance is created. This is usually before anything else is seen.
Opened is called when the application has successfully started.
Closing is called before the app closes.

So since we want to attach out menu when the app is about to show its first window we’ll implement Opening. Copy the declaration and paste it into AppDelegate.cs after the existing App method. And yes type in a {} following it to indicate the method has no code yet.

One thing we need to do is alter the signature of the method to lets the compiler know that our application subclass has overridden the super class Opening event. To do that we need to change the VIRTUAL to OVERRIDE in the method signature.


To add the menu to our application its one line of code

      NSApplication.SharedApplication.MainMenu = new AppMenu("Test");

Note there are STILL no attached menu handlers ; but if you run and select the application menu you should see there IS a Quit menu item there

For the Quit menu item we’re going to add that one to the Application – unlike others which might need to be attached to a specific window or control.

To do this we write whatever method we want to be called when the quit menu item is selected. And then we tell the application what menu item should call this method when we select it.

First lets write the method to call when the menu item is selected.

We can, quite literally, name it just about ANYTHING we want. But, picking good names is useful so we’ll create a method in the AppDelegate.cs named QuitMenuitem_Action which I hope is indicative of what this will do 😛
This method doesnt return anything, so its return type should be void.
It DOES get called with two parameters – one, the sender, which is of type object, and the event arguments, of type EventArgs.

So our method signature should look like

  void QuitMenuItem_Action(object sender, EventArgs e)

followed by a pair of empty { }

And the ONLY code that needs to be in here is a call to, you guessed it, Quit

void QuitMenuItem_Action(object sender, EventArgs e)
{
      Quit();
}

To make it so the App menu item, Quit, runs this code when the item is selected we ned to attach the two. It makes sense to do this in the same spot we created the menu.

If you want you can look in the definition of Application again.
There you will see that Application has a dictionary of menu handlers.
The key is the menu item, and the value is the method to call.
So we can set the Application.MenuHandlers using code like

 MenuHandlers = new Dictionary<MenuItem, EventHandler<MenuEventArgs>>()
 {
   { AppMenu.QuitMenuItem,  QuitMenuItem_Action}
 };

This few lines is VERY dense but we can make sense of it

MenuHandlers is a property on Application we’re going to set to
a new Dictionary
But what’s all the rest of <MenuItem, EventHandler<MenuEventArgs>> ?
The difference here, unlike Xojo, is that we can EXPLICITLY TYPE what the key and value MUST be. Xojo’s dictionary only uses variants so strong typing of dictionaries isn’t possible. C# directly supports strong typing of the keys & values.
So this Dictionary<MenuItem, EventHandler<MenuEventArgs>> says we are creating a dictionary that uses MenuItem for keys and the values are EventHandler that get MenuEventArgs as their parameters. Absolutely unambiguous what can go in there.

And the following

 { AppMenu.QuitMenuItem,  QuitMenuItem_Action}

adds one item to that dictionary with the Quit menu item as the key and our brand new method we just wrote as the menu item handler.

Now if you run and select Quit from the application menu your app should now quit.
Simple stuff to do in Xojo – and it is here as well but the explanation of how this all works takes time & images 🙂

And now as promised

ADDING CONTROLS !!!!!!

We can close the AppDeletage now as we dont need to make any more changes there for now.

Adding controls & event handlers is all done in the MainWindow.cs we created before. Open that now.

Just like with Application where we perused the framework class to see how things worked we’ll go look at the Window class. This class is MUCH more complex than the last we looked at. But again we are looking for protected virtual methods that are ones we can override to add functionality to our Window subclass.

The one we will override is

protected virtual IEnumerable<Control> SetupControls ()
{
    return new Control[0];
}

The implementation in place creates an empty array of controls. Copy the declaration and we’ll paste that into our Window subclass.

Again we need to change virtual to override so the compiler knows we’re stating this method overrides the one in the baes class.

In our Window we will usually, but not always, want to declare a variable to hold a reference to a control. If we want to refer to that control in other code, event handlers, etc it’s easier to keep a reference to the control than it is to dynamically find it on the layout all the time.

So we’ll add a property to our subclass

 TextField textfield;

I’d put this declaration right after the declaration of the subclass

Note that we CAN also alter the visibility of this by prefacing it with private ( or any of the many others that exist in C# https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/accessibility-levels) Public, protected and private are all very similar to how Xojo uses them.

The code in SetupControls then has to create the control with its initial set up and add it to the window.

Creating a new control is about what you would expect. You use the NEW keyword and the classname. You can browse the framework to see what constructors are available. Some controls have several. Most however have a nice easy one that takes 4 coordinates for the left, top, width and height. We’ll use that one :

   textfield = new TextField( 10, 23, 80,  23);

And we can also fill the field with some text

   textfield.Text = "not edit no select";

And now we just have to return the right kind of item.
IEnumerable is an INTERFACE – exactly like in Xojo.
And it just so happens that an array implements that interface !
So we can return a new array of controls like

  return new Control[] { textfield };

Now if you run you will find you can edit the text in the textfield.
Cut copy and paste wont work just yet as there is no EDIT menu and the OS relies on that existing to make the textfield work as expected.

I’ll leave adding that as an exercise 🙂

Tinker around and see what other control you can work with and test things out.
Note theres lot there but not all are 100% complete

The project so far

Creating our Window in C#

So far when you run the project it will show a main window.
But this is because we created the kind of project we did with a main storyboard and an entry in the Info.plist that told macOS what should be the main window.

It isn’t one we created in our new framework.

Lets rectify that.

First open Info.plist and remove the entry for NSMainStoryBoardFile. Click on the small red X icon at the right end of the entry name.

As well remove the Main.storyboard item from the project. Right click on it and select Delete.

At this point IF you run the app wont open any windows, but should still run (Check the main menu bar to verify)

Now to create our “default window” we’ll add a class to our project

Name this new class MainWindow

Notice that the IDE has no idea what superclass this new class should inherit from. Lets fix that.

Recall that in C# we MUST tell the compiler what items we are going to be “using”. Since the Einhugur framework includes a definition for a Window we can tell our new class to inherit from that by adding a using clause
using Einhugur.Forms;
following the using System; that already exists and altering the class declaration to
public class MainWindow : Window

This style says “the class MainWindow inherits from Window”
And the using clause helps the compiler find the declaration of Window in the Einhugur.Forms package

The other thing we can do is remove the Constructor – public MainWindow() since we dont need to do anything special in it

But how will this window get “set up” ? Note there is NOT visual designer in which we can set properties like size, placement, title etc.

We’ll add a method to our new window that takes care of all this. In Xojo this also happens just the IDE writes the code based on your visual design.

In this case its a method that the base Window defines that does nothing that we can override with our own so we can set things how we want.
Add a method to the class by just typing in between the { and } that follow the class declaration

    // much like the constructor in Xojo
    protected override void SetupWindow(WindowCreationParameters prm)
    {
        prm.Left = 200;
        prm.Top = 100;
        prm.Width = 600;
        prm.Height = 400;
        prm.Title = "My first window";
        prm.InitialPlacement = WindowPlacement.Center;
    }

One other thing is the application doesnt know that it should show this window when it starts.

Switch to the AppDelegate and we’ll add an override of the Opened method. This one is much like Xojo’s Opening event when the app starts. This gets called automatically as part of the application startup

    protected override void Opened()
    {
        var window = new MainWindow();

        window.Show();
    }

When you run now you should get one window opened.
Note that there is still some work to do as we haven’t attached any menu bar. Without a menu bar the QUIT menu item doesn’t appear or function so you have to KILL the running debug app by pressing the square STOP icon

Here’s my app so far

Getting Started with C#

Of course to follow along you’ll need to download and install VS for macOS

Once you have it you can easily start a new “solution”
This is MS’ term for what might roughly be the equivalent of a Xojo project (although its a bit more than that) But for now “Xojo project” is close enough.

Select “New”

Select Mac app in the left hand pane send select “Cocoa app” and make sure the language elector is set to C# (you can use others supported by C# but I’m going to focus on C#)

Press Continue

Give your project a name – I used getting_started

Note that in this pane you can select which version of macOS you want to deploy backwards to. Leave it set to macOS 10.14 for now.

Since we’re going to use a different overall framework we arent interested in a document based app either.

Press Continue

Note that GIT integration is built right into the IDE.

Save the project in whatever location you like.

Press Create and Visual Studio will do its thing to create everything needed.

Once it has you should see a screen something like the following.

Now if you wanted you could write a traditional macOS app in C# using the entire macOS framework (which oddly enough MS has done a decent job documenting)

However, the whole point of this tutorial is to use an alternate more “Xojo like framework”

Visual Studio has a nice package management system called nuget built right in. This makes it easy to add in various “libraries” other authors have made available and keep your version up to date as the author updates their code.

Lets add the package from Einhugur

Right click on the top item in the left hand “navigator”

You should get a menu like the following

Select Manage Nuget Packages

You’ll see a dialog that has a very long list of packages that are available to be added to projects. There are packages for dealing with AWS, JSON, Azure, Unit Testing, Redis, REST API’s, and tons of other things.

Fortunately there’s a search field to help us narrow down the item list to the one we’re looking for.

In the search field type in Einhugur

Check the checkbox next to the package and press the Add Package button in the lower right

You’ll get asked what “project” to add the package to. Since we only have one project in this solution the dialog offers to add it to that one. Press the OK button and the package will be added.

ABOUT C# and VS

A “solution” can have many projects in it so it can make sharing code between the different project in the solution really simple, You can have a desktop app, a web app, a mobile app (iOS and Android) all in the same “solution”.

And now we’re ready to start altering the default code we were initially given when we created the solution.

In C# you have to tell the compiler what other bits of any project your going to use. You do this with a “Using” directive. In Xojo everything is global so you rarely have to do this. In C# using .Net the range of libraries is so vast its a requirement. And because there are often several different implementations for something like JSON you have to say which one you’re using – you could use several in different parts of your project (although you might regret that)

In VS, unlike in Xojo, each item in the left hand pane is a “file” a single file on disk. And VS is, for all intents and purposes a text editor for those files (albeit a very smart one).

When you double click an item in its left hand navigator it will open a tab with that item in the tab – the entire item.

What we want to start editing is the AppDelegate.cs file
Double click it to open it.

Since we’re going to make this application a Einhugur Forms one we’ll need to add the using clause
using Einhugur.Forms;

right below
using AppKit;
using Foundation;

As well since we’re not using macOS classes directly we’ll change the code for the class to

namespace getting_started
{
	[Register ("AppDelegate")]
	public class App : Application
        {
	   public App ()
		{
		}

           static void Main(string[] args)
           {
              Application.Init(typeof(App), args);
           }
    }
}

While all this looks daunting its not so hard in reality

namespace getting_started defines a namespace that all our project code can be in. Unlike Xojo “modules” a namespace in C# can span multiple files.

[Register (“AppDelegate”)] tells the C# compiler the following code implements the “AppDelegate” protocol. Its much like an interface.

public class App : Application declares the class App as a subclass of Application. In Xojo you’d set the super property.

public App () declares the CONSTRUCTOR for the App class. You can have several that vary by their signatures. Our code in this case doesnt need to do anything hence the empty { } that follows it.

static void Main(string[] args) declares the MAIN ENTRY POINT for the application. This is the FIRST code that will be run when this application starts up (even before the App constructor) This code basically calls the constructor of App and all that instance to initialize.

Thats it for code we need to write.

We do need to remove one file from the project since it servers the same purpose as the Main method we just added.

Right click on Main.cs and remove it from the project.

And now you can click “Run”

Heres my copy of the project as it sits now

Adventures in C#

Yeah after all these years I’ve started writing some code in C#

Mostly as a way to work in something else
But also as a way to learn another language that I _might_ end up needing to use for client work. Thats a whole different story.

So I started just using a framework put together by Björn Eiríksson

Any first it was just learning how to write code, add event handlers, and generally just getting used to how this all worked, C# syntax (some very handy things there) and poking about.

For all this I’ve been using Visual Studio for macOS.
Not VSCode – which is a VERY different product – but MS Visual Studio Preview for macOS.

Its not as capable as VS for Windows – but its not bad and has evolved a lot since I first started poking around with it.

I’ll try & post my adventures with it here.
And probably also on INN

Switching

I’m happy to se Xojo has decided that maintaining bug base software is not the business we are in
However, the issues that many people have complained about are not JUST about the tool

Some have characterized their feelings about Xojo as Expected behavior working is not Xojo’s strength

And thats not the result of what tool is used to track bug reports or api proposals

That is is a lack of process in how they do what they do. A rigorous process for making sure what goes out the door works as specified would reduce surprises when betas go out to users.
But I don’t believe they have such a thing.
Sure they changed from Feedback to Issues to have abetter tool for tracking whats in each release. Great !
All that does it give you better tracking of changes.
It doesnt mean that when you make changes you have done rigorous testing of those changes and QA before it gets to users

Was a unit test created that exposes the bug?
And JUST that bug ?
Then the bug fixed and now the unit test passes ?

And do those unit tests get run on every check in so regressions are found & fixed long before they get to an alpha build, never mind a beta ?

Trust me I realize that UI testing this way is tougher to automate.
But its necessary to automate what you can (hello AppleScript & Accessibility !)
And where you cant make darned sure you try & test everything that could be affected.
And if you say it works on Xojo Cloud make sure that is tested too !
Don’t just assume that because it works on my desktop it will work there too !

Issues might be a great tool but it alone is not likely to be the answer to better quality releases

Numbers after the change

Xojo recently shifted way from Feedback, their home grown bug tracker, to Issues from GitLab. As part of this they’ve added a number of bots that seem to automatically deal with cases.

Comparisons to my old #’s are difficult because Issues tracks multiple tags per case where Feedback basically had a single status

There are some easy comparisons

In Feedback I had 58 Archived cases, several of which I requested be reopened,
In issues there are 99, with several I’ve asked to be reopened.
Archived is a label I’d like to see tossed out as it is, at least in my experience, a label that just plainly says “Thanks for the report we just don’t care to look at this.”

In Feedback I had had 433 Open cases.
As of today in Issues there are 117.
When I look at my closed cases I see a lot that have been updated recently. But I just don’t have the energy to review all the lines closed in the last 2 weeks. I see some marked as duplicates of other cases.

Beyond that its hard to do direct comparisons.

One thing Issues makes possible is that it is possible to quickly search for all kinds of labels

Like, bugs, archived, not marked fixed, by design, implemented, not actionable or not reproducible

Such a query shows, as I write, 4148 of these

Labelled Bug, reproducible and archived a paltry 11

Or reported by other users

Numbers 2022-05

Current count of my cases in Feedback

Archived 58
Closed (already Exists) 12
Closed (by Design) 49
Closed (Duplicate) 55
Closed (Misc) 37
Closed (No Longer Reproducible) 5
Closed (Not Actionable) 9
Closed (Not Reproducible) 48
Fixed 9
Fixed & Verified 133 (broken down as)
       Build 2
       Compiler 1
       Crashes & assertions 5
       Database Plugins 1
       Debugger 1
       Documentation 37
       Examples 2
       Framework – All 16
       Framework – Web 4
       Framework – Windows 2
       Framework – macOS 4
       IDE – Auto Complete 6
       IDE – Build Automation 2
       IDE – Code Editor 5
       IDE – Constant Editor 1
       IDE – Debugger 1
       IDE – Enum Editor 1
       Ide – Errors & Warning Panel 2
       IDE – FileIO 3
       IDE – Inspector 10
       IDE – Language Reference 1
       IDE – Layout Editor 4
       IDE – Library 1
       IDE – Menu Editor 1
       IDE – Miscellaneous 6
       IDE – Navigator 1
       IDE – Refactoring Tools 1
       IDE -Scripting 1
       IDE – UI 3
       IDE – UI – Menus 1
       IDE – UI – Tabs 1
       N/A 6
       XojoScript 1
Implemented 5
Implemented & Verified 16
Open 433
Resolved 2