MonoTouch Programming in Visual Studio

TL;DR

Never underestimate the little time sinks of switching between IDEs regularly. To write MonoTouch code in Visual Studio 2010 (debug/deploy still requires MonoDevelop on a Mac), go get VSMonoTouch. If you have any issues getting it going, you may need to toss in some project file tweaks.

Background

I’ve been programming with MonoTouch for a few months now using MonoDevelop. I really enjoy learning new things (even if MonoTouch saved me from learning Objective-C), but switching IDEs always tosses a few kinks in my productivity. I have tweaked a number of key bindings in MonoDevelop to match Visual Studio, some at the cost of my ability to adapt to the Mac’s defaults that are normally used everywhere. At one point I switched copy and paste to use Ctrl in MonoDevelop, but then I kept screwing up outside of the IDE. Regardless, I have become fairly productive in MonoDevelop from simply adapting to the new system through repetition (often screwing up when I switch back to Windows now).

I don’t really have a problem with MonoDevelop most days, but I definitely prefer the Windows system of maneuvering windows and working on multiple displays. Even if I were a Mac-only person, I would hate how full-screen mode works on a Mac. While I have adapted to my new MonoDevelop workflow, I definitely miss having multiple tabs open in a single project; to open multiple instances of MonoDevelop on a Mac, you even need a simple hack. Having to flip around between MonoDevelop and Chrome as I drink from the MonoTouch learning firehose only compounds the window management issue.

Nothing seems to get you around the need for a Mac when testing/debugging/deploying a MonoTouch project, but having Visual Studio as your primary IDE for all your .NET projects can definitely speed things up.

VSMonoTouch

Enter VSMonoTouch by Jonas Follesø (follesoe on GitHub).

This Visual Studio VSIX add-in (warning: requires a non-free Visual Studio) seems to create a system for allowing Visual Studio to recognize the MonoTouch framework and its project type and use the correct DLLs for compiling. For simplicity’s sake, just follow the instructions in the project README for your first run. If that doesn’t work, start looking for tweaks.

The final process I used was simply moved the VSIX install step from first to last on the instructions list from the README (with absolutely no reason to explain why it worked). Regardless, feel free to try some restarts on the off chance you have issues.

  1. Copy the MonoTouch binaries from your Mac development environment to your Visual Studio 2010 development environment. Copy all the files from /Developer/MonoTouch/usr/lib/mono/2.1/ on your Mac to C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v1.0 on your PC.
  2. Add a RedistList-folder under your newly created v1.0-folder. Download the FrameworkList.xml file and add it to the RedistList-folder.
  3. Download and run the vsix-package from the github page.

Code Reference Quirks

It seems that some systems have an easier time getting VSMonoTouch to run than others. On my Windows 7 machine with Visual Studio 2010 (10.0.40219.1 SP1Rel), .NET 4.5, and various Visual Studio 2012 free components; I had a few issues getting things just right. The first three times I tried things out, I simply couldn’t get Visual Studio to acknowledge the project type. It would load the solution I have from MonoDevelop but leave the projects unloaded.

I tried all sorts of variations on the FrameworkList.xml file and gave up for a while.

mscorlib

Today, I decided to try again after I noticed a few updates to a project issue with mscorlib. That wasn’t the issue I was having, but I was hoping anyone trying to solve this issue may accidentally find a solution to help my problem. Oddly, after installing the DLLs first and then the VSIX, it all started loading correctly but with some compile errors and warnings.

  • Error: “An assembly with the same identity ‘mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′ has already been imported. Try removing one of the duplicate references.”
  • Warning: “No way to resolve conflict between “mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089″ and “mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089″. Choosing “mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089″ arbitrarily.”
  • Warning: “There was a mismatch between the processor architecture of the project being built “MSIL” and the processor architecture of the reference “C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorlib.dll”, “x86″. This mismatch may cause runtime failures. Please consider changing the targeted processor architecture of your project through the Configuration Manager so as to align the processor architectures between your project and references, or take a dependency on references with a processor architecture that matches the targeted processor architecture of your project.”
  • Warning: “Found conflicts between different versions of the same dependent assembly.”

This is where that [mscorlib project issue] came into play. There was a note on the VSMonoTouch README about making sure to have explicit mscorlib references, but I already did. Checking the box on the “Do not reference mscorlib.dll” project property, though, removed those errors.

VSMonoTouch mscorlib.dll issue fix

If you are a fan of tweaking csproj XML directly instead of through the project properties editor, feel free to add this node to any compilation PropertyGroups manually.

<NoStdLib>true</NoStdLib>

System.Web.Services

After fixing the mscorlib.dll issues, though, I got a new error popping up. This final compile error was coming from code I wrote, so that was a good sign (I guess).

  • Error: “The name ‘HttpUtility’ does not exist in the current context”

Since I am writing an application that interfaces almost entirely with the web-based JSON API I wrote, there are a few places where I am sending back user content to that system. The URL encoding I use simply hits HttpUtility.UrlEncode. In MonoTouch, you need to make sure you reference System.Web.Services to get UrlEncode. But, in Visual Studio Land, the .NET 4.0+ DLL doesn’t have such a method. You can fix this issue with a static version reference on that DLL. There may be a version-agnostic way to do this, but I ended up editing my csproj file to point to the specific version found in the MonoTouch DLLs.

<Reference Include="System.Web.Services, Version=2.0.5.0" />

I will probably have to update this manually whenever a new version hits MonoTouch, but I definitely can live with that.

VSMonoTouch In Use

After getting the loading and compile errors worked out, I now have a MonoTouch solution building successfully in Visual Studio 2010. It contains a core project shared with the Sierra Trading Post Android app (using a few compiler directives) and my MonoTouch project containing almost entirely UI-related code. I write some code and it tells me whether it will compile correctly against the MonoTouch DLLs. I haven’t tried abusing the reliability of this system with any features that are not part of Mono (e.g., async/await) or MonoTouch (e.g., dynamic) yet.

Since my project is currently synced through Dropbox, I just save what I have on Windows and roll on over to the MacBook to run things on the simulator or deploy them to a physical device and/or TestFlight (which is far better than sliced bread, at least for getting your app out to multiple devices). MonoDevelop will even automatically update your project files if you already have it open, though I don’t recommend editing on both systems simultaneously without having something between them to handle conflicts that are bound to arise.

Closing and Re-opening tabs in Visual Studio with Ctrl+W

Visual Studio 2013 Undo-Close Update: Since the prior options for re-opening closed tabs fell apart with the release of Visual Studio 2013, you will need the newly released Productivity Power Tools 2013.

Update: now with the ability to re-open closed tabs with Ctrl+Shift+T. This also allows you to re-open tabs closed by a project file reload, which is fantastic!

Ever tried to close a tab in Visual Studio 2010/2012 with Ctrl+W. If so, you find yourself selecting the current word in your text editor (Edit.SelectCurrentWord). I don’t use that shortcut, though I could see it being handy over my usual Ctrl+Shift+Right-/Left-Arrow. I do, however, use Ctrl+W to close windows/tabs in just about every other program I use. In order to make that shortcut work for your Visual Studio editing, you just need to assign it to File.Close instead.

For the visual, here’s a snapshot similar to what you will want (note: I already made this change before snapping a pic, so yours may look slightly different).

Visual Studio Keyboard Options

  1. Go into the Tools->Options menu.
  2. Select Environment->Keyboard in that window.
  3. Type “File.Close” in the “Show commands containing” field and select it in the list when it shows.
  4. Choose “Text Editor” for the “Use new shortcut in” field.
  5. In “Press shortcut keys” field, press Ctrl+W.
  6. Click “Assign” to make it happen.
  7. Close the Options window with the “OK” button.

Now, you can happily close windows with Ctrl+W in Visual Studio.

Next step

Figure out how to get Ctrl+Shift+T to bring back the last closed window. If I find a way, I’ll post it.

Update (2012-02-16): Re-open previously closed tabs (with PowerCommands for Visual Studio 2010 [also works for Visual Studio 2012])

As Sergey Vlasov pointed out in a comment, the PowerCommands for Visual Studio 2010 adds the ability to “Undo Close” on previously closed tabs. Since it adds them as commands to Visual Studio, you can also override the default keyboard shortcut (Ctrl+Shift+Z) to a more web-browser-esque shortcut: Ctrl+Shift+T. If you already had this installed for Visual Studio 2010 when you started using Visual Studio 2012, just install the PowerCommands for Visual Studio 2010 again and it will offer to add it to Visual Studio 2012. You will still need to make the shortcut assignment in 2012.

Visual Studio Keyboard Options (Edit.UndoClose)

Just like with your favorite web browser, this will cycle through previously closed tabs, resurrecting them from their graves and restoring your cursor location to right where you left off when you closed them. Amazingly enough, this also works when Visual Studio closes your active windows when a project reloads.

Adapting Visual Studio code styling differences for open source project contribution

Background

Today, while incorporating Lee Dumond’s MVC Route/URL Generation Unit Tester into a project, I found a desire to contribute some code I thought would make the package easier to use. Unfortunately, the project code formatting looks nothing like my preferred conventions (some form of 1TBS, I guess). Until Visual Studio offers a way to distribute code style settings to source control consumers easily, I needed a different option.

While preparing demos for a mobile web development talk for the Cheyenne Computer Professionals group, I stumbled on Mike Minutillo’s tip for running a “demo” instance of Visual Studio where I could sandbox my presentation settings optimized for an elderly VGA projector. This sparked an workaround idea for dealing with multiple formatting settings of various projects I may work on.

Rather than force my conventions on the project (generally not acceptable) or give up on my own style (generally not acceptable), I decided to try using a “demo” instance of Visual Studio with that projects styling conventions set.

  1. Right-click where I want the shortcut.
  2. Specify a path to Visual Studio 2010 using the /RootSuffix option.
    1. On 64-bit Windows, %programfiles(x86)%\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe" /RootSuffix YourStylingNameHere
    2. On 32-bit Windows, %programfiles%\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe" /RootSuffix YourStylingNameHere
  3. Give the shortcut a name. I tend to go something like this: “Visual Studio (SomeProjectName)”.

Using this method, I can create a few common formatting variations. Then, whenever I want to work on a given project, I will just slap a new Visual Studio shortcut pointing to the appropriate suffix matching that projects formatting style.

I created an instance of Visual Studio that uses the default settings. Any new project I want to play with that uses those settings gets a custom VS shortcut that points to my “DefaultVsFormatting” root suffix.

By keeping the suffix names consolidated, all projects using those settings are present in that instance’s recent projects, both in the File menu and the Start Page (and its pinned projects).

Drawbacks

While it is great to be able to spawn up a Visual Studio instance, it does complicate some things. If I have multiple instances of Visual Studio running with different prefixes, I have no way of telling which is which without knowing what project I opened from what prefix instance.

It also presents a problem for someone who develops on multiple machines. I want the RootSuffixes I use to be identical on all machines. For the default settings, assuming I have Visual Studio in the same location on every machine, I could simply keep these %programfiles(x86)%-based shortcuts on a shared location like my Dropbox folder where they would work for all machines. If I have custom settings, though, I would need to keep copies of the settings folder data and registry settings.

Keeping the file system part consistent seems easy enough; I could just use a symbolic link to point Visual Studio to them in their shared location (change to your own path to settings folders).

mklink /d %LocalAppData%\Microsoft\VisualStudio\10.0DefaultVsFormatting %userprofile%\Dropbox\VisualStudioSettings\DefaultVsFormatting

There are also registry keys that are part of this process, too. Unfortunately, it appears that all the formatting settings are maintained there. This would take some extra work and make any changes difficult to propagate. After I create a suffix variant, I need to export the registry settings for the two registry keys (folders in the tree).

  1. Run ‘regedit’.
  2. Export the two prefix-based keys that are created (“10.0DefaultVsFOrmatting” and “10.0DefaultVsFOrmatting_Config”, in this case).
  3. Import those two keys on any other machines.

From there, any time I make a config change, I need to repeat this process on any machine that shares these settings. Not ideal, but it gets the job done.

UPDATE:

Unfortunately, after trying this, I found out many of the registry settings are set to explicit user-based paths. I need to try making those paths relative to various path variables (e.g., %userprofile%) before exporting the registry key and importing it elsewhere, but that may blow up Visual Studio. If you use the same user on all of your development machines, you are likely fine with this process; if not, you will need to tweak them accordingly.

Alternative (Visual Studio settings files)

Jon Galloway’s comment on Mike’s post has a valid point. It is definitely a useful option to just use a custom Visual Studio settings file (via Paul Stubbs) that can be imported as desired. I ended up using the /RootSuffix route for a couple reasons:

  • Every time I make a common change to the settings (admittedly rare), I would need to update all my various settings files.
  • Importing settings files would take more steps than launching a shortcut, at least unless there is some command-line option I haven’t learned yet where I can use to give Visual Studio the settings for that run.

No matter what method I use, it gets even more difficult to manage these situations when someone has a tool like JustCode or ReSharper installed on their machine. They would then need to maintain settings files for these tools as well, potentially needing to uninstall them for a given project to keep them from going all Rambo on the foreign code.

Conclusion

Ideally, any given Visual Studio-based project would just have a file shared among contributors that enforces the code styling conventions chosen for the project.

Until settings are a part of a project this solution works great on a small scale but is a bit difficult to scale to multiple machines. That said, I only have two machines on which I actively write code, so I will live with the hassle for now.