Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically create controls / objects in C# MonoMac (NSButton, NSLabel)

I'm trying to create an NSButton and an NSLabel in code. I'm able to get it created, but I don't know where I should add it and then wire it up for connections.

I don't want to use XCode (w/ Interface Builder) because these controls would need to be instantiated dynamically.

  • Should I add the button in NSApplicationDelegate in the mainWindowController?
  • Do I wire it up at the "Window.cs" file?

Can someone point me in the right direction to dynamically create and wire up objects in MonoMac / C#?

Thanks in advance, Yves

like image 602
Yves Schelpe Avatar asked Oct 19 '22 18:10

Yves Schelpe


1 Answers

Doing research in Apple docs and Xamarin docs I came up with the following solution. I have no idea if it would work in more complex scenarios, but it's a start.

I have no idea if this is best practice. Either way, I hope this helps other people as well. If I find more information I will update this.


Creating The AppDelegate

Some introduction

Showing the window

The AppDelegate class will create the window and other NSObjects (such as NSButton etc..)

First the override the method FinishedLaunching - in that method we create the window (NSWindow) - see lines at var window = new NSWindow(...). After that there's some boiler plate to

  1. Make the window show up starting from the top left window.CascadeTopLeftFromPoint (new PointF (20, 20));
  2. "Show" the window using window.MakeKeyAndOrderFront (null);

Creating the button

The method CreateCloseButton() will generate a button with title, appearance etc.. already set. For an easy guide to pick wich BezelStyle, check out this link: [ http://psionides.eu/2014/10/06/a-guide-to-nsbutton-styles/ ].

Adding the button to the window

This section is again inside the method FinishedLaunching. Steps taken:

  1. Make a rectangle (or RectangleF) for the "subview" of the button. This means creating a rectangle where the button lives in. If you would make this too small, the button will not show up fully, but it'll have some missing edges for example. Code is var closeButtonRect = new RectangleF (8, 8, closeButtonSize.Width, closeButtonSize.Height);.
  2. Next we have to make our button aware that this rectangle is what it will live in by saying: closeButton.Frame = closeButtonRect;.
  3. Then we add the button (or NSView) to our window. window.ContentView.AddSubview (closeButton);.

Wiring up a click event to the button

This section is again inside the method FinishedLaunching. But it could easily be set up elsewhere. Basically this works as c# events (see snippet below).

// Attach an event to the button. When "Activated" / "Clicked" it will close the application.
                closeButton.Activated += (object sender, EventArgs e) => { 
                    NSApplication.SharedApplication.Terminate(closeButton);
                };

Full Code

AppDelegate Class

using System;
using System.Drawing;
using MonoMac.Foundation;
using MonoMac.AppKit;

namespace MonoMacTest02
{
    public class AppDelegate : NSApplicationDelegate
    {
        public override void FinishedLaunching (MonoMac.Foundation.NSObject notification)
        {
            // Get the button
            var closeButton = CreateCloseButton ();
            // Get size and create rectangle for the view                 
            var closeButtonSize = closeButton.Frame.Size;
            var closeButtonRect = new RectangleF (8, 8, closeButtonSize.Width, closeButtonSize.Height);
            // Apply the rectangle to the frame
            closeButton.Frame = closeButtonRect;

            // Attach an event to the button. When "Activated" / "Clicked" it will close the application.
            closeButton.Activated += (object sender, EventArgs e) => { 
                NSApplication.SharedApplication.Terminate(closeButton);
            };

            // Creating the NSWindow object
            var window = new NSWindow (
                new RectangleF(0, 0, 400, 300), // Sets the size of the window
                NSWindowStyle.Titled, // Style of the window
                NSBackingStore.Buffered,
                false
            ) {
                // Adding a title
                Title = "MonoMacTest02 (Adding a button)"
            };

            // Add our button to the window
            // AddSubView expects an NSView object. All UI controls are derived from NSView, so we can add the 'closeButton' itself.
            window.ContentView.AddSubview (closeButton);

            window.CascadeTopLeftFromPoint (new PointF (20, 20));
            window.MakeKeyAndOrderFront (null);
        }

        // Creating the button
        private NSButton CreateCloseButton() {
            var closeButton = new NSButton ();
            closeButton.Title = "Close";
            closeButton.BezelStyle = NSBezelStyle.Rounded;

            closeButton.SizeToFit ();

            return closeButton;
        }
    }
}

Program Class (static void Main())

using System;
using MonoMac.AppKit;

namespace MonoMacTest02 {
    public class Program {
        static void Main(string[] args) {
            NSApplication.Init();

            var application = NSApplication.SharedApplication;
            application.Delegate = new AppDelegate();
            application.Run();
        }
    }
}

All remarks and suggestions are welcome.

like image 159
Yves Schelpe Avatar answered Oct 22 '22 08:10

Yves Schelpe