# Tuesday, 27 July 2010

Tonight, I did a presentation on "Developing a .NET application onMac OS X using MonoMac" at the Alaska .NET Users Group meeting. I hope everyone enjoyed my presentation and learned something from it! I'd appreciate any feedback anyone has to offer!

The download link is at the end of this blog post. If you download the source, you will probably want to review all the posts I've written on MonoMac as well.

Source Code


MovieTimes source code

Tuesday, 27 July 2010 22:53:29 (Alaskan Daylight Time, UTC-08:00)
# Monday, 05 July 2010

I’m working on my presentation for the Alaska .NET Users Group. My goal is to build an app that consumes a web service, and displays the data. After getting the web service piece going, the next step was to display that data in a NSTableView.

I battled for hours and hours trying to figure out how to create a NSTableViewDataSource, and it turns out I was making things way to complicated. I did some searching on the web, but couldn’t really find anything except a post by John Moshakis on the Mono-osx mailing list which gave me some hope that someone had figured it out.

I emailed John, and he was gracious enough to send me some source code to work from. It turns out, I what I had wasn’t far off the mark, I just needed a few pointers.

The DataSource Code

  1. using System;
  2. using System.Collections;
  3. using MonoMac.Foundation;
  4. using MonoMac.AppKit;
  5. using MovieTimes.BusinessLogic;
  6. using System.Collections.Generic;
  7.  
  8. [Register("MyItemDataSource")]
  9. public class MyItemDataSource : NSTableViewDataSource
  10. {
  11.     public List<MyItem> MyItems { get; set; }
  12.  
  13.     static MyItemDataSource () {
  14.     }
  15.  
  16.     [Export("numberOfRowsInTableView:")]
  17.     public int numberOfRowsInTableView (NSTableView aTableView) {
  18.         if (MyItems == null)
  19.             return 0;
  20.         return MyItems.Count;
  21.     }
  22.  
  23.     [Export("tableView:objectValueForTableColumn:row:")]
  24.     public NSObject objectValueForTableColumn (NSTableView aTableView, NSTableColumn aTableColumn, int rowIndex) {
  25.         return new NSString(MyItems[rowIndex].Name);
  26.     }
  27.  
  28.     public void Items(List<MyItem> items) {
  29.         MyItems = items;
  30.     }
  31. }
  32.  
  33. public class MyItemDataSourceDelegate : NSTableViewDelegate {
  34.     public event EventHandler<MyItemChangedEventArgs> MyItemChanged;
  35.  
  36.     public MyItemDataSourceDelegate ():base()  {
  37.     }
  38.  
  39.     public override void SelectionDidChange(NSNotification notification) {
  40.         var table = notification.Object as NSTableView;
  41.            
  42.         var ds = table.DataSource as MyItemDataSource;
  43.            
  44.         var rowNum = table.SelectedRow;
  45.            
  46.         if (rowNum >= 0 && rowNum < ds.MyItems.Count)
  47.             OnMyItemChanged(new MyItemChangedEventArgs(ds.MyItems[rowNum]));
  48.     }
  49.        
  50.     protected void OnMyItemChanged(MyItemChangedEventArgs e) {
  51.         if (MyItemChanged != null)
  52.             MyItemChanged(this, e);
  53.     }
  54. }
  55.    
  56. public class MyItemChangedEventArgs : EventArgs {
  57.     public MyItem MyItem { get; set; }
  58.        
  59.     public MyItemChangedEventArgs(MyItem i) {
  60.         MyItem = i;
  61.     }
  62. }

The code is kind of long, and I’ve removed all the normal guard code you would use for the sake of brevity. But lets dissect the code. The first part, lines 8 – 31 is the actual data source. It simply listens for a few messages (numberOfRowsInTableView and objectValueForTableColumn) and allows items to be added to the data source (line 28). The next part, lines 33 – 54 fire off an event when the selected item has changed in the NSTableView instance.

The Window Code

  1. public override void WindowDidLoad () {
  2.     base.WindowDidLoad ();
  3.  
  4.     var myDel = new MyItemDataSourceDelegate();
  5.     myDel.ItemChanged += ItemChanged;
  6.  
  7.     this.someTable.Delegate = myDel;
  8.     this.someTable.DataSource = new MyItemDataSource();
  9. }

In the window controller, paste the above code to have code run when you window loads. For WinForms people, public override void WindowDidLoad is the equivilent of protected override void OnLoad().

So what does the window controller code do? First off, we create our delegate (note, delegates in Cocoa are not the same thing as in C#), and wire up to the changed event, then we assign the newly created delegate and a data source to our table.

Any questions, thoughts or feedback? Hit me up in the comments, or follow me on twitter.

C# | Mac OS X | Mono | MonoMac
Monday, 05 July 2010 08:00:00 (Alaskan Daylight Time, UTC-08:00)

For the past week or so, I've been developing a couple of sample apps in Mono with Cocoa on my Mac. In that time, I've struggled quite a bit, and learned quite a bit. One of the biggest things I've learned is things are much harder when you try and mix-in paradimes for which things were not designed.

Take for example NSTableView. Because Objective-C is duck typed, you set Delegate property of your table to this (self in Objective-C) and implement the selectionDidChange method and you will get notified when a row is selected.

Because C# is not duck typed, you have to write a whole lot of ceremony code to get notified when a row is selected. And figuring out that ceremony was a huge battle. I wouldn't have won the war without the help of John Moshakis. Another thing thats not supported is Registering a generic type, or setting a generic .NET type the property of a Cocoa widget.

That means the ceremony code has to be duplicated every time, for every different type of object. I actually tried to make a generic version of my Databinding to an NSTableView blog post, but I was thwarted by an "Invalid IL exception." Hopefully this is just a defect, and not a limitation when dealing with Cocoa.

I would file a defect on this issue with the mono project, but Novell requires you to create an account to add a defect to their bug tracker. I can understand why they want you to do this, but its not a very good way to encourage participation from the community. But I guess it is a particularly good way to discourage drive-by defect reports.

.NET | Mac OS X | Mono | MonoMac
Monday, 05 July 2010 01:28:36 (Alaskan Daylight Time, UTC-08:00)
# Sunday, 04 July 2010

It took me quite a bit of battling tonight, and some of it turned out to be an OS caching issue but I managed to set the application icon for my test MonoMac app.

Take your favorite image and convert it to a .icns file, I used the http://iconverticons.com/ website. Drop the output of that into the root of your MonoDevelop project. Next, right click on the file and set the “Build Action” to content.

Double click on “Info.plist” in the root of your project, add a new item and set its key to “Icon File”, and value to “icon” or what ever you named your icon file. Note, you do not need to put the .icns extension in the value field to make things work.

image

Sunday, 04 July 2010 08:00:00 (Alaskan Daylight Time, UTC-08:00)
# Saturday, 03 July 2010

I’ve followed MonoDevelop for a long time. In that time, I’ve seen it go from a barely usable product, to now a fairly capable IDE. Out of the box, it look and acts much like Visual Studio. I do like that that a dedicated unit testing tab is present as a constant reminder that, “Hey, you know you should probably write those unit tests you’ve always talked about writing.”

One thing I was somewhat surprised to not see, at least on the Mac edition of MonoDevelop is a built-in scheme for the VS keybindings. On the down side, I have been able to crash MonoDevelop when I didn’t have some setup code in the right place and I ended up with a null ref trying to talk to some Cocoa widgets.

More to come as I spend more time with MonoDevelop.

.NET | Mono | MonoMac
Saturday, 03 July 2010 08:00:00 (Alaskan Daylight Time, UTC-08:00)
# Friday, 02 July 2010

When Miguel De Icaza first announced MonoMac back in April I was pretty excited! Its been my goal for the past two years to write a half-decent, native looking, Mac OSX application with .NET. I’ve looked at the various Cocoa binding strategies for Mono and always found them lacking. Some like CocoaSharp haven’t been updated in ages, and the WinForms stuff on Mac looked plain fugly. Like Windows 95 fugly.

I found Michael Hutchinson’s quick-start post on writing a simple .NET app using MonoMac. Because I had previous experience using Interface Builder, I was able to muddle my way through building his simple app. But at the end, I wanted something more. “Hello World” is great to show you the most basic syntax of a language, and maybe how to use the compiler, but it honestly does nothing for me.

So, I set out to write real, although somewhat contrived image viewing application. Having an extensive background writing WinForms, ASP.NET and some WPF apps, the hardest part for me was trying to figure out the Cocoa equivalent to things like PictureBox, and FolderBrowserDialog. But Google as always was my friend.

I’m not going to dive into how to write the app tonight, but I will post a screen shot, and the ImageViewer source!
image

Nits

Yes Cocoa is based on an MVC architecture, and yes I should have put some of the code into a business class, but I didn’t.

.NET | C# | Mac OS X | Mono | MonoMac
Friday, 02 July 2010 07:22:00 (Alaskan Daylight Time, UTC-08:00)