SemanticMerge Blog

Dissecting SemanticMerge, Part 4: Cocoa 101 for WinForms/WPF developers

Monday, March 24, 2014

Ever thought about writing a Mac GUI in C#? You’re probably used to Buttons, Panels, Dialogs and the like, but how do they map to the Mac counterparts? Well, this is what we try to cover in this post: a Cocoa 101 for WinForms developers.

Background

Mac development is a new world for a Windows developer. New tools, new subsystems, new OS, new languages…

We wanted to develop a Mac native UI for SemanticMerge and then we faced some decisions: stay in C#? Move to Objective-C? Get used to the Interface Builder or ignore it?

Since other teams might be facing a similar situation we thought it would be good to dissect our SemanticMerge GUI and use it to explain some Mac GUI development essentials.

Before entering the Cocoa 101 we had to decide whether we should go for Objective-C or not and whether we should go for a native UI or try something like Qt.

In a previous post we also covered some MonoMac basics and then one interesting topic: should you use the Interface Builder or go hard-core and code the entire GUI?

Welcome to Cocoa

You start and write your first “hello world” in Xamarin Studio but then you’ve to figure out how to really structure your app. And then is when worlds collide.

As Windows developers we were used to Buttons, Forms, Panels, Splitters and all but… that’s not the same thing when you get to Xamarin.Mac. You’ve to get used to the Cocoa and a new set of controls.

As I mentioned first, this is what I’m going to do by dissecting our SemanticMerge application. And for the sake of simplicity, I’ll start with a simple dialog, the start up window:

And let’s now go and dissect it:

The picture shows all the controls we use in this simple dialog and I think it is a good way to get familiar with Cocoa if you come from a Windows background.

Let me share thoughts on the picture above:

  • The Window has a ContentView which is the one you’ll use to place more controls inside. The ContentView is an NSView.
  • The NSBoxes are somehow similar to Panels in WinForms. You can use them to contain other controls.
  • Buttons: all buttons in Cocoa will be of type NSButton, but then you’ll set properties to it depending on the style of the button you want to use.
  • Something similar happens with NSTextField: you can use a TextField as a WinForms TextBox, but you can also configure it to be like a Label. In the picture I defined the ‘edit boxes’ as NSTextFields with “Editable = true” and “Bordered = true”.

Alignment with Constraints

Once you meet a few controls is time to know how to align them. You can always just place them in the Window ContentView with global coordinates, but it won’t help if you need your NSBoxes to grow with the window, or your buttons to keep aligned to the right.

While we were all familiar with Anchors in WinForms, to code UIs in Mac we need to learn the Constraints.

Constraints are the set of rules you use to define where each control is located, aligned and so on.

The ‘language’ to define constrains can be intimidating at first, but it is really easy to learn and very powerful.

I’ll first explain how constraints are defined and later I’ll cover how to code it in C#.

Let’s start with a very simple scenario: just a window with two buttons as the figure shows:

If we don’t set the constraints correctly (step 2) then when the window grows the buttons will stay on the same position, losing the correct relative position “anchored” to the bottom right of the window.

In step 3 the constraints are correctly set and the buttons keep the relative position to the bottom right.

How do we achieve this? With the ‘magic of Mac constraint rules’.

The rule to specify the horizontal alignment is very simple:

  • H: stands for horizontal rule.
  • [cancel(150)] refers to the “cancel” button (later I’ll explain how do you tell the system that the button will be named ‘cancel’ when specifying contraints.
  • -10- means you’re separating the two buttons with a “10 size” separation.
  • [ok(150)] gives a 150 size to the “ok” button.
  • -10- is another separator.
  • | the last vertical bar on a horizontal constraint rule refers to the right border of the window. It is the piece of the constraint saying “keep everything aligned to the right”.

The language is easy to remember and very powerful as you can see.

Since we’re only specifying the “right border” it means everything will be relative to the right.

Notice I didn’t set a “left bar” which means the buttons will be ‘anchored’ to the right.

What if I edit the rule and modify it in the following way:

“H: |-10-[cancel(150)]-10-[ok]-10-|”

I have added a “left border” so basically I’m saying:

  • The “cancel” button should be linked to the left border with a 10 points margin.
  • Then there will be another “10” separator between the buttons.
  • And the “ok” button will grow as much as it needs in order to keep a right margin of 10 with the right border.

The result will be something like:

Now that we know how to set up the horizontal constraints, the vertical ones will be really easy to figure out:

We specify 2 different rules where we set the vertical margin between the buttons and the bottom border of the window, and also the button height (or vertical size).

Now that we “master” the constraints, it is not hard to figure out the layout of the SemanticMerge launch window:

Remark: you ALWAYS have to specify both the vertical and horizontal constraints. Otherwise nothing will be rendered. It happened to us 🙂

Defining constraints in C# and MonoMac

Now that the constraint language is crystal clear ;-): how is this set on a MonoMac application?

Look at the following code listing which is able to create a Window like the following:

    public override void AwakeFromNib ()
    {
        base.AwakeFromNib ();
        // button created programatically
        NSButton button = new NSButton();
        button.Title = "Click Me";
        // button added to the window
        NSView contentView = Window.ContentView;
        contentView.AddSubview(button);
        // now we set the constraints
        // nothing works if you do not specify this!!
        button.TranslatesAutoresizingMaskIntoConstraints = false;
        // now let's add the names of the controls
        // to the constraints system so we can
        // reference the controls by name in the
        // constraints rules
        var views = new NSMutableDictionary();
        var constraints = new List();
        views.Add(new NSString("button"), button);
        // and here go the constraints
        constraints.AddRange(
            NSLayoutConstraint.FromVisualFormat(
                "H:[button(150)]-10-|", 0 , null, views));
        constraints.AddRange(
            NSLayoutConstraint.FromVisualFormat(
                "V:[button(23)]-10-|", 0, null, views));
        contentView.AddConstraints(constraints.ToArray());
    }

Setting the constraints in code is straightforward as you see, but simply don’t forget to:

  • Specify horizontal and vertical constraints.
  • Set the “TranslatesAutoresizingMaskIntoConstraints” to false!

Wrapping up

We’ve discussed about whether going native or use multi-platform UI toolkits, then we went through the ‘imperative vs designer based’ UI implementation alternatives and later we introduced some very common Cocoa controls.

Finally we dissected the “launcher dialog” in SemanticMerge to explain how constraints work.

Hope you find this post useful and happy Mac C# hacking.

GUI development: should you design it or code it – Dissecting SemanticMerge, Part 3

Sunday, March 23, 2014

Our question here was: “should we use the designer or code an imperative UI?

As you have just seen using the Interface Builder is really simple, just drag and drop, getting used to the new controls and the UI of the designer and so on.

Xamarin Studio doesn’t provide its own designer it simply relies on invoking Interface Builder, which is not bad since they’re not reinventing the wheel.

But, there are some concerns in my opinion:

Each time the Interface Builder modifies one of the .xib files (files containing XML defining the interfaces) Xamarin Studio gets notified and rebuilds whatever linked code it needs. It always worked for us with pet projects but I wouldn’t really like to be in the situation, 6 months after starting the project, with tons of code written, to find some sort of ‘conversion error’ when linking the .h files populated by Interface Builder with the Xamarin code. I hope I’m wrong here, but simply I don’t want to be in that situation.

Now, more about UI designer vs plain code: recently I read this blog post about creating “imperative UIs” with C# in the Xamarin blog. When I found this post we already had finished the SemanticMerge UI programming in “imperative mode”.

There were various reasons why we went the ‘imperative way’ and we coded our entire interface completely avoiding the Interface Builder:

  • First we wanted to avoid any potential issue with the ‘automatic conversion’ as I mentioned.
  • Prior to starting with Mac we developed a GTK# UI for SemanticMerge, to give it native look and feel on Linux. We used MonoDevelop 4 there, which is great, but its interface designer is… well, far from looking solid. So we went the ‘hardcore’ way and created the entire UI with code. It can sound like an overkill (it *did* sound crazy to me years ago) but read the next bullet point first.
  • We’ve been developing Plastic SCM (www.plasticscm.com) with a WinForms UI for almost 9 years now. We always used the Visual Studio designer and… you know what? I hate it. It looks great for a toy application, you just go and drag and drop your controls and everything looks fine. But use it for a decade and you’ll find out:
    • That the infamous .resx will break or simply won’t get correctly updated and you will lose alignments or some event handlers from time to time. Time wasted.
    • At least the WinForms designer doesn’t enforce good practices: I hate when I find auto-generated names in controls such as Form1 or Label1 and so on. Of course you can ask your team to… not do it this way, but the tool *helps* doing it wrong.
    • Suppose you redesign a Form and then you need to move part of the UI inside a new panel and then add more things to the form… well, you’ll need to play with the “anchors”, cut and paste… and pray. BTW the entirely regenerated automatic code will be a nice thing to merge…
    • Since it is very easy to just “throw controls on the window” then probably many unneeded ones will hang around, like panels inside panels and other beauties.
    • Keep the right margin for buttons and controls in all forms… looks easy, but someone will have to hand write the margin space again and again… wouldn’t a constant help?

As counter-intuitive as it might sound (tell it to my younger self coding a MFC UI and missing Delphi), for long running projects I truly believe it is better to go and code the UI: you can refactor code to make it more readable, you’ll think twice before adding a control, you’ll name everything correctly, you’ll just have to slightly modify the code to change the hierarchy of objects inside a window… and you won’t have to depend on error prone UI designers.

Dissecting SemanticMerge, Part 2: Enter MonoMac

Wednesday, March 19, 2014

Note: this is the second part in the Dissecting SemanticMerge series. Part I is How we develop for Mac using C# and MonoMac.

So, if you’re going to write a C# “native looking” app for Mac the choice is MonoMac a.k.a. Xamarin.Mac. It is pretty well documented and it looks solid.

The first thing you’ll have to do is to go and grab a Xamarin Studio installer and you can play with it for free before you decide to go commercial.

Installing is easy and then you’ll be on a very familiar environment since it feels like Visual Studio (it is the famous MonoDevelop now in Xamarin disguise, pretty polished. We’ve been using it for months and it is pretty good. Of course, MonoDevelop 4 is also solid on Linux. Having used all versions since their first release, version 4 is really a plus).

The .xib files and the Interface Builder

I strongly recommend that you go and complete one of the basic Xamarin.Mac tutorials. You’ll start getting familiar with objects starting with NS (NSApplicationDelegate, NSObject and many more) and then with the Interface Builder.

The Interface Builder is the Xcode (the native Mac IDE to develop Objective-C, developed by Apple) interface to design user interfaces.

Interface Builder is the typical interface designer, similar to what you’d expect as a WinForms or WPF developer.

You can go and drag a button (a “Push Button” in Mac jargon) to the window area and you have created your first button. You can edit its properties and change the title:

Then you can drag the button to the MainWindowController.h to create an outlet or an action. This is the way in which the code will discover the button (or any other control) you have just created.

Once you’re done with this, you’ll be able to add an event to your code as follows:

Just notice I’m overriding the AwakeFromNib method which is like the “Load” method in WinForms applications. It is invoked just when the window is activated.

You can learn more about this following the Xamarin tutorials, so I’ll just continue focusing on what’s not in the tutorials 🙂

Dissecting SemanticMerge, Part 1: how we develop for Mac using C# and MonoMac

Tuesday, March 18, 2014

Objective-C is the language of choice when you go for Mac (and iPhone) but thanks to Xamarin now more than half a million C# developers are able to code for Apple platforms in their language of choice. And this is something good if you’re a Windows developer who need to develop a new app on Mac.

I’m going to share the things we learned while developing SemanticMerge for Mac using C# and MonoMac, and I’d like these posts to be the sort of writing I wish we had when we started our journey :-). This is the part one of a series of posts dissecting SemanticMerge to explain how we develop with C# and Mac

To Objective-C or not to Objective-C

The obvious choice when going to develop a Mac app is going for Objective-C. It is the native language so there’s no better choice.

That being said, there are some situations when you might consider sticking to C#:

  • Your app will be based on an extensive codebase written in C#. When that’s the case, rewriting in Objective-C or making it interop somehow can be time consuming.
  • The deadlines are tight (aren’t they always? :P) and getting proficient with Objective-C is not an option.

While I think the first reason is pretty acceptable, I’m afraid the second one can be a dangerous excuse for a real world application. Let me elaborate a little bit further: you’ll need to learn the foundations of the Mac environment in order to develop a professional app (I mean, anything that is not just a demo).

  • You’ll have to read Objective-C code since it is the main source of documentation and unfortunately there’s not so much info in C#.
  • You’ll have to get familiar with the Cocoa objects to build your app anyway.

I hope we can help reducing the learning curve with these posts 🙂

Native toolkits

Once you’ve decided C# is the right choice (otherwise you’d be reading Objective-C guides already :P) you’ll probably wonder if you should go for a native ‘window toolkit’ or not.

Let me explain it in detail: “wouldn’t it be awesome to have some sort of UI toolkit where you can write your app once and run it everywhere? I mean, this is the sort of thing Mono does for .NET programs, isn’t it?” – Someone would say.

Well, yes and no. We’ve developed WinForms apps (check the Mac and Linux screenshots in our gallery) for years and we have run them on Linux, Windows and Mac. You think you save time at the beginning because you have a “write once run everywhere” sort of thing. You don’t. The app looks great on Windows, but it looks alien on Mac and Linux. And users will notice immediately, specially the Mac ones.

So, no, don’t go for a “one size fits all” here. You’ll have to spend time writing a MonoMac app even if you already have a wonderful WPF or WinForms one.

“What about things like Qt then?” – I hear someone crying – Well, yes, Qt is cool if you’re a C++ developer, but the C# wrappers, while they’ve been around for ages, seem to lack solid documentation and evolution.

Conclusion

We decided to go with C# and MonoMac because we were very familiar with the language (we love C#, we’d love C# for system programming even more :P) and we had to reuse most of our codebase.

We also used the development of Semantic in C# and MonoMac as an experiment (or pilot project if you prefer) before porting the entire Plastic SCM GUI to Mac.