# Thursday, July 08, 2010

I use and enjoy my Microsoft 4000 keyboard very much. Its the best keyboard I found since the original Microsoft Natural Keyboard. Key placement makes sense, is comfortable to type on, I love the media keys (but honestly, why no love for next and previous track?).

The one thing I don't like however, is how Mac OSX handles PC keyboards. Why does home/end move me to the beginning and end of my document? Everybody knows they are supposed to move the cursor to the beginning and end of the current line. Thankfully, we have Double Command to help fix the issues! If only it could make the page up/down keys function like on the PC...

Thursday, July 08, 2010 6:54:57 PM (Alaskan Daylight Time, UTC-08:00)
# Tuesday, July 06, 2010

After I finished creating a sample application to test out the capabilities of Mono on the Mac, I figured I should create the same application in Objective-C to have an accurate understanding of what the pain points are in each technology.

The first big pain point I've come across is creating the bindings to call a web service in Objective-C. Apple provides a utility called WSMakeStubs. The utility makes creating the stubs easy and painless, or so it would seem. Out of the box the code doesn't compile.

For reasons unknown to me, WSMakeStubs utility makes duplicate method names. The issues people have with WSMakeStubs are so bad, almost every article I've read, everyone advocates using NSUrlConnection and NSXMLParser and rolling your own service calls.

Its 2010 Apple, how about coming up with a viable solution to making web service calls? Even PHP has a good web services proxy generator.

Tuesday, July 06, 2010 11:15:56 PM (Alaskan Daylight Time, UTC-08:00)
# Monday, July 05, 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, July 05, 2010 8:00:00 AM (Alaskan Daylight Time, UTC-08:00)