MonoMac “Exception has been thrown by the target of an invocation” when accessing outlet

If you’re getting a ‘Exception has been thrown by the target of an invocation’ exception when trying to access an outlet variable, it could be the outlet has been hooked up wrong. The outlets must be hooked up to the File Owner, which is most likely to be your controller class. Xcode presented the view rather than the controller in the editor panel, so I had hooked up all of my outlets to the view instead of the controller by accident.

Posted by Dan in Mac, 0 comments

Cocoa Popup window in the Status bar – MonoMac Port

Vadim Shpakovski way back on July 2011 released code for a popup window in the status bar, and now in August 2012 I have ported it over to MonoMac with a few tweaks! If you don’t care about the guide below, you can access the source at Github.

The implementation is largely the same as used in Vadim’s implementation, with a few tweaks to make it simpler, more .NET-like and more extensible. There’s still more work that needs to be done to make it truly modular architecture-wise, but I’ve made the classes themselves easily extensible with clear extension points.

High Level Overview

The entry point is the StatusPanelController, this controller creates the icon in the status bar. It takes in a controller that inherits from PanelController so that you can create your own custom views if necessary. When the user clicks on the icon, the controller will call OpenPanel() and ClosePanel() in the PanelController.

The PanelController is the controller for the panel that opens – it’s responsible for all rendering.

BackgroundView is the background for the panel we display, you can think of it as the panel itself. It renders the arrow, border, and background. For this reason the panel you use must have a BackgroundView, additionally the panel itself should be effectively non-styled, with all standard window chrome removed.

That’s basically it!

BackgroundView

BackgroundView is a special view that represents the popup panel. At the top of the source file are various constants for controlling how the view should be rendered. ArrowX is necessary so that we know where the middle of the status bar icon is. The arrow will centre itself on this point.

To render the view we override DrawRect, and provide our own custom drawing using an NSBezierPath to do most of the work. Take note that the coords .NET use are reversed on the Y axis, .NET’s origin is in the top-left, while OS X’s origin is in the bottom left.

PanelController (and a little note on MonoMac Animation)

PanelController is the most substantial class in the entire project. This controller is responsible for the display of the panel itself, this means it needs to handle the animation of the panel, as well as updating the BackgroundView with the position of the status icon, should the window be resized. HandleWindowDidResize handles the arrow position, updating the BackgroundView whenever the panel is resized. Meanwhile we have two events, WillClose and DidResignKey that we use to know when to close the panel. We don’t want the panel just disappearing, we want a nice smooth animation!

OpenPanel() is responsible for displaying the panel in a smooth way. First of all it works out the position the panel needs to be, this is based on the icon position. Next we set up the panel for display by ensuring critical state, and adding a teeny bit of a debug Easter egg. If you press shift, or shift + option, you slow down the animation, and optionally output debug information relating to the upcoming display.

Finally we animate the panel into view. Note that we cast the Animator property of the window, this is because by default the Animator property is of type NSObject. The Animator is actually a proxy for the full object, so we can just cast it to the ‘real’ type, and set our new post-animation properties. We then finish our animations, and let OS X do the rest!

ClosePanel() is the opposite of OpenPanel() and just animates the panel away.

Panel

Panel is a very slightly customised implementation of NSPanel. We just add an extra property so that we can use controls in the panel that require the keyboard, such as text fields.

StatusItemView

This is the view that will be displayed in the status bar. It’s fairly self-explanatory, with different images depending on the state of the button. There’s a GlobalRect property so that we can locate the icon in the screen and position the panel.

For rendering we override DrawRect, and do it largely ourselves. We first draw the background into the view, optionally highlighted. Next we draw the requisite image (the icon) in the centre of the view. We use an updated method call over the one used by Vadim because the original has been deprecated – it’s not even available in MonoMac!

Finally we track the MouseDown and MouseUp events, rather than just MouseUp. A ‘click’ is considered when the user both mouses down and up, in the same view. If the user does this, we fire the StatusItemClicked event.

StatusPanelController

Finally we have the controller that actually brings it all together. The controller could do with a little more work to make it genuinely re-usable, since it uses hard-coded values for the images, as well as the view used for the status icon. Fortunately re-factoring these out into dependencies would be fairly trivial.

At construction we create all of our required controllers and views, this creates the icon in the status bar.

We hook into the clicked event from StatusItemView, and toggle the panel as neccesary.

Finally we implement IDisposable so that we never leave an icon in the status bar by accident – that would be very bad! We also have a finalizer so that no matter what, the icon will end up removed from the status bar when the controller is garbage collected.

Posted by Dan in Mac, Programming, 6 comments

Running multiple instances of MonoDevelop on Mac

By default OS X will only let you run a single instance of any app, which is OK if the app is designed with multiple windows & a single instance in mind. MonoDevelop is a different beast, and sooner or later you’re going to want to run at least 2 instances of it, here’s how:

First run the AppleScript editor, and enter the following code:

do shell script "open -n /Applications/MonoDevelop.app/"

Now save the script somewhere easily accessible, make sure to set the ‘File Format’ to ‘Application’. I chose the name ‘MonoDevelop Launcher’:

Now the only problem left is the icon, it’s most likely the AppleScript icon, rather than the MonoDevelop one:

Use ‘Get Info’ to get the info for both your new launcher, and MonoDevelop. Click on the icon for MonoDevelop and press CMD+C. Now click on the icon for your script, and press CMD+V. The icon should now be correct:

References: Based on answer by ‘Subfuzion’ as StackOverflow

Posted by Dan in Guides, Mac, Programming, 0 comments

wait_fences: failed to receive reply: 10004003

This error is cryptic and can have any number of causes, but the most common are:

  • Performing animations when the view isn’t on screen (use viewDidAppear, not viewWillAppear)
  • Failing to call super when overriding a method
  • Calling something in the UI from a thread other than the main UI one
  • Calling UI methods that dramatically change the view (such as presenting / hiding main views) too quickly
  • Calling UI methods before an alert has been dismissed

Basically the error is related to the UI. The message appearing in the output may not reflect the code that actually triggered it – so to debug you need to isolate the code that’s causing it. Your first port of call should be callbacks from alerts, or other popups. For me it was the UIImagePicker, I fixed it like so:

protected void FinishedPickingMedia(object sender, UIImagePickerMediaPickedEventArgs e)
{
    var picker = sender as UIImagePickerController;

    if (picker == null)
        return;

    picker.DismissModalViewControllerAnimated(true);
    if (picker == _picker)
	_picker = null;

    // Work with the image here

    // Bug fix for fences issue
    BeginInvokeOnMainThread(() =>
    {
        // CODE THAT INTERACTS WITH THE UI HERE
    });
}

The pertinent code is the BeginInvokeOnMainThread block, this is fixing the wait_fences issue. It looks like the callback method isn’t being executed on the UI thread. I’m not sure if this is an iOS SDK thing, or a quirk added by MonoTouch. It could also be that the picker is still animating away when I start tweaking the UI, causing the issue. For example messing about with the UI in the Clicked event of a UIAlertView can sometimes cause minor issues, moving the code to the Dismissed event fixes the issues completely.

Posted by Dan in C#, iOS, MonoTouch, 0 comments

Using UIGestureRecognizer in MonoTouch

Gesture Recognisers are a great feature added in iOS 3.2 (ages ago!), and using them in MonoTouch couldn’t be simpler. I’ll skip over a discussion on how they work, if you want more info on the recognisers themselves, be sure to check out the Apple documentation.

Selectors

UIGestureRecognizer instances use selectors to call back methods in your class. Selectors are supported in MonoTouch, you just need to do a little more work:

[Export("ViewTapSelector")]
protected void OnViewTapped(UIGestureRecognizer sender)
{
    MessageLabel.Text = "View Tapped";
}

Essentially you need to create a method, then mark it for export. This tells the MonoTouch compiler to make the method callable by ObjC code. Make sure the containing class is decorated with the Register attribute (ViewControllers are automatically registered).

First Recogniser

Setting up a UIGestureRecognizer is very easy:

var tapRecogniser = new UITapGestureRecognizer(this, new MonoTouch.ObjCRuntime.Selector("ViewTapSelector"));
View.AddGestureRecognizer(tapRecogniser);

This creates a new recogniser, with a callback and assigns it to the root view for the controller. You don’t need to worry about garbage collection since the view will retain the recogniser. You can access all of the recognisers for a view by using the GestureRecognizers property.

That’s it!

Surprisingly that’s all there is to it! You can download an example project here, or just view the code snippet below to flesh out the principles:

Sample Code

private void SetupGestureRecognisers()
{
    var tapRecogniser = new UITapGestureRecognizer(this, new MonoTouch.ObjCRuntime.Selector("ViewTapSelector"));
    View.AddGestureRecognizer(tapRecogniser);

    var doubleTapRecogniser = new UITapGestureRecognizer(this, new MonoTouch.ObjCRuntime.Selector("ViewDoubleTapSelector"));
    doubleTapRecogniser.NumberOfTapsRequired = 3;
    View.AddGestureRecognizer(doubleTapRecogniser);

    var longPressRecogniser = new UILongPressGestureRecognizer(this, new MonoTouch.ObjCRuntime.Selector("LongPressSelector"));
    View.AddGestureRecognizer(longPressRecogniser);

    var panRecogniser = new UIPanGestureRecognizer(this, new MonoTouch.ObjCRuntime.Selector("LabelPanSelector"));
    DragLabel.AddGestureRecognizer(panRecogniser);
}

[Export("ViewTapSelector")]
protected void OnViewTapped(UIGestureRecognizer sender)
{
    MessageLabel.Text = "View Tapped";
}

[Export("ViewDoubleTapSelector")]
protected void OnViewDoubleTapped(UIGestureRecognizer sender)
{
    MessageLabel.Text = "View Triple Tapped";
}

[Export("LongPressSelector")]
protected void OnLongPress(UIGestureRecognizer sender)
{
    MessageLabel.Text = "View Long Pressed";
}

[Export("LabelPanSelector")]
protected void OnLabelPan(UIGestureRecognizer sender)
{
    var panRecogniser = sender as UIPanGestureRecognizer;

    if (panRecogniser == null)
        return;

    switch (panRecogniser.State)
    {
        case UIGestureRecognizerState.Began:
            _originalPosition = DragLabel.Frame.Location;
            break;

        case UIGestureRecognizerState.Cancelled:
        case UIGestureRecognizerState.Failed:
            DragLabel.Frame = new RectangleF(_originalPosition, DragLabel.Frame.Size);
            break;

        case UIGestureRecognizerState.Changed:
            var movement = panRecogniser.TranslationInView(View);
            var newPosition = new PointF(movement.X + _originalPosition.X, movement.Y + _originalPosition.Y);
            DragLabel.Frame = new RectangleF(newPosition, DragLabel.Frame.Size);
            break;
    }
}
Posted by Dan in C#, iOS, MonoTouch, Tutorials, 4 comments

Getting Back / Forward mouse buttons working in Mac OS X

If you want to use mouse buttons #4 and #5 to go forward / backward in Mac OS X out of the box you’re going to be disappointed, and end up with just a scroll icon appearing.

There’s a few utilities you can use to fix this:

  • Microsoft IntelliPoint – Only works with MS mice, doesn’t seem to work in Mountain Lion
  • Logitech Control Centre – Only works with Logitech mice, apparently quite buggy now
  • Razer software – not tested, will only work with Razer mice anyway
  • Steermouse – Getting increasingly flakey with new OS X versions
  • USB Overdrive – Not been in development since Snow Leopard, doesn’t seem to work 100% of the time anymore
  • ControllerMate – Works!

ControllerMate to the rescue!

ControllerMate is actively developed & maintained, and offers an incredible amount of customisation for all HID peripherals. So not only will it sort out your back / forward issue, it’ll also solve the mouse acceleration issue – if that’s a problem for you. This guide will cover back / forward only, though.

1. First download and install ControllerMate.

2. Reboot and launch ControllerMate.

You’ll now be presented with a scary as hell screen that looks like you’re laying out circuit boards, rather than fixing a major limitation in OS X.

The diagrams in place on first launch are a kind of mini tutorial, telling you how you can do a few things. You can either leave them in place for future reference, or delete them to clean up the view.

The first step is to create a new Programming Group:

3. To do this, right-click in the sidebar and select ‘Create Programming Group”.

4. Afterwards, right-click on the new group, and select ‘Create Programming Page’.

5. Now right-click on the new group again, point to ‘Create Driver Configuration’, then select your mouse.

You can name your new items in the ‘Inspector’ window to the right.

6. Click on your programming page to display an empty grid.

7. In the ‘Palette’ to the right, select ‘Controllers’ from the drop down list. Find your mouse, then drag button #4, and button #5 to the grid.

8. Now select ‘Output’ from the drop down list in the Palette. Drag an instance of ‘Keystrokes Building Block’ underneath each of your mouse button instances.

You should now have something like this (without the green lines):

9. Link the blocks, by dragging from the button’s green hotspot, to the action’s green hotspot. Just as in the screenshot above.

10. Click on the keystroke block for button #4. In the Inspector window, click on the ‘Keys’ tab, then click on ‘Capture’. Enter they key combination for ‘Back’ (Command + [), then press stop.

If the command doesn’t appear correctly, click on ‘Open Keystrokes Palette’, and drag the buttons from the virtual keyboard to the window, as seen above.

11. Do the same for button #5’s keystroke block, but this time use the command for forward (Command + ]).

12. Click on the driver configuration item in the sidebar, and set buttons #4 and #5 to ‘None’.

You’re now done! Backward / Forward should work immediately in all apps.

But now my VM / Other App doesn’t respond to buttons #4 and #5!

This is a problem as a result of disabling the buttons and remapping them to forward / back. Fortunately there is a solution!

  1. Click on the group in the sidebar
  2. In the ‘Inspector’ window, check ‘Activate items when these applications are:’, select ‘running’
  3. Add all of the apps that you want to add back / forward support to the list.

Now the mouse will work in all applications. If an app supports backward / forward, remember to add it to the list above.

More VM

Not all VMs support the extra mouse buttons, even if they’re receiving them. If you’re having trouble, try following my follow-up guide for Parallels.

Posted by Dan in Guides, Mac, 22 comments

Error: Unable to find fileDFUI.exe please verify your install is correct.

I was getting the error ‘Error: Unable to find fileDFUI.exe please verify your install is correct.’ when trying to run an Azure project locally. MS have a rather hefty workaround here which I really didn’t want to use (especially since the error will come back after a while).

An easier workaround is to backup your ServiceConfiguration and ServiceDefinition files and delete the Azure project from your solution, also delete all traces of the Azure project from your solution directory.

Next add an Azure project to your solution (don’t add any roles). Add the roles manually using your existing projects (right-click on ‘Roles’ within the Azure project and select ‘Add > <X> Project in Solution’.

Restore your backed up service config files and you should be good to go!

Posted by Dan in Azure, General, 1 comment

Ninject & Constructor Arguments

I had an issue where I needed to created an instance of a class with a custom constructor argument using Ninject 2. I initially tried something like this:

return IoC.Get<CountryChecklist>(new Parameter("selectedItems", countries, false)).RenderCountryChecklist(model);

However, this is unreliable. The solution is fairly simple, use a ConstructorArgument instead of Parameter:

return IoC.Get<CountryChecklist>(new ConstructorArgument("selectedItems", countries)).RenderCountryChecklist(model);
Posted by Dan in C#, 0 comments

NSubstitute – Falling off a log easy mocking

Call me crazy, but I like my programming to be easy as pie. If it’s complicated or I have to jump through some hoops then something is decidedly wrong.

This is where NSubstitute comes in – it makes mocking dead easy, and the great thing is it integrates really well with Ninject for really easy unit testing with IoC. The NSubstitute home page has a great example of how the mocks work:

//Create:
var calculator = Substitute.For<ICalculator>();

//Set a return value:
calculator.Add(1, 2).Returns(3);
Assert.AreEqual(3, calculator.Add(1, 2));

//Check received calls:
calculator.Received().Add(1, Arg.Any<int>());
calculator.DidNotReceive().Add(2, 2);

//Raise events
calculator.PoweringUp += Raise.Event();

And when something goes wrong, it’s pretty succinct with the error messages:

CallNotReceivedException : Expected to receive call:
    Add(1, 2)
Actually received (non-matching arguments indicated with '*' characters):
    Add(*4*, *7*)
    Add(1, *5*)

Ahhh I do love a nice simple API with fluent support.

Posted by Dan in C#, Programming, 0 comments

Network Order and String Encoding

As a follow-on from my post on floating point values and endian swapping, I thought I’d write an article on strings. String encoding is fairly complicated due to the fact that we’re now living in a large global community – ASCII simply won’t cut it any more. On the positive side, if you only need ASCII you can send it across the network as-is. Since it’s only a single byte, there is no worry about endianness.

The problem is when dealing with string encoding that can go over a single byte, so-called multi-byte encoding. This is very likely if you need to support languages other than English. Rather than worry about endianness, BOMs, and other character encoding headaches; may I humbly suggest you try UTF-8. UTF-8 is completely backwards-compatible with ASCII, yet supports the entire unicode character set. It uses the minimum number of bytes for each character (good for saving bandwidth) and is inherently immune to endian issues (for for your sanity). In C# encoding to UTF-8 couldn’t be simpler:

Encoding.UTF8.GetBytes(myString);

The only issue with UTF-8 is that you can’t just say that the string is X number of bytes long based on the number of characters. Characters can require anywhere from 1 byte to 6 bytes. The simplest solution to this problem is to encode the string into a byte array, then prefix with an int that contains the length of the entire string in bytes. When reading the string back in, you can read in the first int then read however many bytes the int specifies.

Posted by Dan in C#, Guides, 0 comments