My name is Michael Hutchinson and I'm a software engineer working for Xamarin on the MonoDevelop IDE and Mono for mobile platforms. Here you can find my journal, projects and photos.

Journal

Razor Preprocessed Templates

When Miguel asked me to investigate making MonoDevelop support using Razor templates in MonoTouch and Mono for Android apps, I realized that it could be done simply and with very few dependencies by taking the same approach as T4 preprocessed templates, which I implemented for MonoDevelop a couple of years ago. Fortunately, this time the hard part was already done: I could use Microsoft's open-source Razor parser instead of writing my own parser. I also found a Visual Studio extension called Razor Generator that was very close in functionality to what I wanted, and was able to use this as a basis for my work. I was able to hook it it into the fantastic Razor editing and code completion support written by Piotr Dowgiallo in the Google Summer of Code this year.

After a few days work implementing, tweaking and tuning (and bouncing ideas off Bojan Rajković), I present Razor Preprocessed Templates in MonoDevelop.

As a basis for this demo, I created new a MonoTouch iPhone Single View application, added a UIWebView to the View's xib, and connected it to an outlet on the controller called webview. However, you can use these templates in any project type.

Just add a new Text Templating -> Preprocessed Razor Template file to the project:

Adding a new Preprocessed Razor Template

You will see that this adds a cshtml Razor C# file to the project, grouped with a C# file that contains the generated code. Like T4 files, this uses the "custom tool" extensibility mechanism. By setting the custom tool property on the cshtml file set to "RazorTemplatePreprocessor", it causes MonoDevelop to use this new custom tool to regenerate the cs file whenever the cshtml file is saved.

The files added by the Preprocessed Razor Template

I wrote a simple Razor page to demonstrate the power of Razor. It uses a simple Razor helper to demonstrate that Razor helpers work correctly. The page also demonstrates using the @model directive to specify the type for a Model property, which easily allows us to pass data into the template before running it. Since this demo is very simple, I just used an int as the model instead of defining a proper model class.

@model int
 
@helper boldtd (int i) {
<td><b>@i</b></td>
}
 
<html>
	<head>
		<title>Multiplication Table</title>
	</head>
	<body>
		<h1>Multiplication Table</h1>
		<table>
			@* Header row *@
			<tr>
				<td/>
			@for (int i = 1; i <= Model; i++) {
				@boldtd(i)
			}
			</tr>
			@* Main table *@
			@for (int i = 1; i <= Model; i++) {
			<tr>
				@boldtd(i)
				@for (int j = 1; j <= Model; j++) {
				<td>@(j * i)</td>
				}
			</tr>
			}
		</table>
	</body>
</html>

When writing this, the Razor code completion was very helpful. It has full C# completion, including locals, helpers and members from the generated class and base class, including the generated Model property:

Code completion for C# in Razor Templates

There's also HTML completion and on-the-fly underlining of HTML and Razor errors:

Code completion and error underlining for HTML in Razor Templates

After saving the cshtml file, you can look at the generated cs file. It's pretty messy, so I won't show it here, but note that it includes a well-commented generated base class. If you want, you can specify a base class using the @inherits directive, so you can pull that generated base class out and share it between multiple templates, or customize it. The template's only dependency is Action<System.IO.TextWriter>, and the default base class's dependencies are only System.Web.HttpUtility.HtmlEncode(string) and System.IO.StringWriter, so it can easily be made to run anywhere. If your target framework lacks the one potentially awkward dependency, HttpUtility.HtmlEncode(string), you can provide an alternative implementation via a custom base class.

More documentation on the generated class and the available directives can be found on the MonoDevelop website.

To use the template, I simply added two lines to my ViewDidLoad method to instantiate the template, generate a string using the Generate() method, and load it into the UIWebView:

public override void ViewDidLoad ()
{
    base.ViewDidLoad ();
 
    var template = new MultiplicationTable () { Model = 12 };
    webview.LoadHtmlString (template.GenerateString (), null);
}

Then run the app, and you can see it in action:

Razor Template running on iPhone

This is a fantastic way to generate HTML pages without pulling in the whole System.Web stack, and I hope you're as excited about it as I am. It isn't available today, unless you build MonoDevelop from source, however the code is committed to MonoDevelop master and should make it into the next 3.x release.

The State of MSBuild Support in MonoDevelop

I occasionally get questions about support for advanced MSBuild features, and my answers are usually fairly short. This post aims to be a more comprehensive description of the current state state of MSBuild support in MonoDevelop, so I can refer people to it. If you've never hand-edited custom targets for an MSBuild file, this doesn't affect you at all, but feel free to read it if you're curious.

MSBuild is the Microsoft build engine that was introduced with .NET 2.0 and Visual Studio 2005. It's the format for the project files of Visual Studio 2005 and later, and has been MonoDevelop's default/native file format since MonoDevelop 2.0. It's XML-based, so it can be handled easily and reliably by tools such as IDEs. It's essentially intended to be consumed primarily by IDEs — but it also has the power of an advanced, extensible build system that lets you do pretty much anything if you're willing to get your hands dirty. Calling it "Makefiles in XML" wouldn't be too far off the mark.

The MSBuild engine and hosting API are part of the .NET framework. Mono has its own implementation called xbuild, which runs on Mac, Linux and Windows. The core features of xbuild are solid, but it's missing some of the advanced features added to MSBuild in .NET 3.5 and 4.0, and some of the common targets such as the ASP.NET web project targets.

MSBuild is extremely complex and exposing all its features in the MonoDevelop GUI would be practically impossible. However, the projects created by the IDE by default use the "common targets" to build the project, which understand a certain number of properties (e.g. "OutputPath") and item types (e.g. "Compile", "EmbeddedResource"), and implement certain targets (e.g. "Build", "Clean") that operate on these items and are controlled by these properties. They also make very limited use of conditions, by conventionally having several groups of properties conditional upon the value of the "Configuration" and "Platform" variables. To edit projects that haven't been hand-modified, the IDE only really has to understand the item types, properties, and targets used by the common targets.

MonoDevelop has an internal project model that represents the projects and their properties and items. When loading the project, MD deserializes the MSBuild file into its internal model, and ignores the items, properties and imports it does not understand. When saving MSBuild projects, MD serializes its internal model into the MSBuild format and substitutes them for the parts of the MSBuild file it understood, thereby preserving the parts of the file that it did not understand: custom items, properties, targets, conditions, and imports.

There are a couple of things the serialization doesn't handle — when hand-edited projects use properties or items as values of any of the standard properties or items. MonoDevelop does not evaluate these — doing so would require a full MSBuild engine — and even if it did, it would not easily be able to present them cleanly in the UI and serialize back any changes to the values. It might be possible to special-case some things, but it's not something that can be fully solved in a generic way. Probably the best we could get would be to have MonoDevelop detect property/item values it cannot handle, evaluate them via the MSBuild engine when loading, make them non-editable with a warning flag in the Project Options GUI, and skip them when serializing.

Wildcards in items paths are a similar problem. For example, evaluating a wildcard in an item when deserializng would result in adding several items to MD's internal model. And in simple cases, we could match all those items back to the wildcard MSBuild item when serializing. So far so good. But what happens if a new file is added on disk outside of MD while the project is open? What happens if the user manually removed a single item in the solution tree? What happens if the user changes the metadata of a single item? In all of these cases, the items can no longer be mapped back to the single wildcard MSBuild item. It would probably be possible to remove the wildcard item and serialize all the items to MSBuild individually — but that might not be what the user expected. This is just one example of how supporting a simple MSBuild feature in the IDE might not be as simple as it looks.

For building the projects, MonoDevelop's story is much better, because it has the ability to build the projects using the actual MSBuild/xbuild engine, thereby supporting all features that MSBuild/xbuild does. There are currently two build codepaths in MonoDevelop: the old internal build engine, and the MSBuild engine. The internal build engine is very old, and predates the existence of MSBuild. It operates directly on MonoDevelop's internal project model, and is extensible via the addin system. The MSBuild engine loads the actual project files into a builder process and builds them using the MSBuild hosting API.

By default MonoDevelop uses the old engine, but the addins for individual project types can opt into using the MSBuild engine for just those projects — Mono for Android does this. Enabling the experimental option "Compile projects using MSBuild/XBuild" in MonoDevelop's preferences (and restarting MonoDevelop) causes the MSBuild engine to be used for all projects. This is marked experimental because it does not work for all project types — for example, there are no MSBuild targets for MonoTouch, MonoMac or ASP.NET projects yet. User projects that depend on MonoDevelop's old custom build command system will not build correctly with the MSBuild engine. And some of the old MonoDevelop custom project types such as translation projects and C/C++ projects would need to be migrated to a new file format before they could even have MSBuild targets.

In general, expansion of the MSBuild support in MonoDevelop is not a high priority for the MonoDevelop team, since these advanced build features are of interest to a very small subset of users, and there are other things that could be done to improve the IDE experience for a much greater number of users. However, it's an area of ongoing improvement and will likely become more important in the future.

MonoMac video from NDC 2011

The videos from NDC 2011 are now online, including my talk Developing .NET Applications for the Mac App Store (direct link). You can also download a printable version of my presentation. Hopefully there will be an official torrent of the videos soon, because there were plenty of other sessions that are worth seeing. Thanks to everyone who helped make it such a great conference!

Correction: In the presentation I said that native objects don't retain references to managed objects, which is incorrect. The problem I intended to refer to is a common coding error where views are retained but their controllers are not, e.g. mainView.AddSubview(new ChildController().View).

Speaking at DevTeach

This week I'm going to be presenting two sessions at DevTeach 11 in Montreal.

My first topic will be Native .NET Apps for the Mac with MonoMac. I'll be taking about MonoMac and the native Mac APIs that it exposes to .NET developers, and how to build native apps that can be deployed to the Mac App store. My second topic will be Using Mono for Native Apps on Mac, Android, iPhone and more. I'll be giving an overview of Mono's most exciting platform integration technologies: Mono for Android, MonoTouch (iPhone), and MonoMac. I'll also explore strategies to share and re-use code between these and other .NET platforms such as Windows, Silverlight and Windows Phone 7.

I'll also be on the DotNetRocks panel to discuss mobile platforms, and outside my talks I'll be happy to discuss any Mono-related topic, especially the technologies I've worked on — MonoDevelop, MonoTouch, Mono for Android, ASP.NET MVC, and the use of Mono in games.

Preview of Xcode 4 Support for MonoTouch

In their recent update of the iOS and Mac developer tools, Apple removed the standalone Interface Builder application and integrated the GUI designer functionality directly into Xcode 4. This was a very significant change and removed several features that were necessary for MonoTouch and MonoMac to integrate with the designer. As soon as Xcode 4 went final, we started working on MonoDevelop support for integrating MonoTouch with Xcode 4's GUI designer, but it's a complex project and will take some time to complete.

For now we recommend using Xcode 3's Interface Builder, which can easily be done even while having Xcode 4 installed. However, I understand that many people are concerned how Xcode 4 will be better supported going forward for MonoTouch and MonoMac, so I've made a screencast to introduce MonoDevelop's upcoming Xcode 4 integration and demonstrate how it works.

MonoTouch integration with Xcode 4

Although XIB files can be opened standalone in Xcode 4, this isn't very useful, as it's no longer possible to define custom types, outlets and actions within the interface designer. Instead the designer is aware of the Objective-C types defined in the Xcode project that contains the XIB file. This means that we have to generate an Xcode project file and synchronize it with the MonoDevelop project. Since Apple doesn't support writing third-party Xcode plugins, we can't make the Xcode designer directly aware of types defined in C# source, so the generated Xcode project also has to contain Objective-C stubs for all the types defined in C#. The Xcode designer now modifies the Objective-C source files when adding outlets or actions, so those changes need to be synchronized back the the MonoDevelop project.

The new model of Xcode integration resolves several outstanding issues in the previous Interface Builder integration. Because the generated project contains all bundle resources (Content and Page files) from the project, they will now be accessible directly from the GUI designer. In addition, all user-defined types are accessible from the designer, not just those defined for the current xib file.

Obviously, synchronizing files and types between two projects in separate applications is complex, and if anything goes wrong it's possible to lose data, so we want to make sure it's as reliable as possible before we release it. We hope to be able to offer a beta of this functionality within the next few weeks.

Speaking on MonoMac at NDC 2011

I'm going to be at NDC 2011 in Oslo, and I'll be speaking about Developing .NET Applications for the Mac App Store. The talk will provide an introduction to MonoMac and the native Mac APIs that it exposes to .NET developers, explain the structure of MonoMac apps and how they can be deployed to the Mac App store, and discuss strategies for code reuse across the platforms supported by Mono and .NET.

If you catch me outside my talk, I'll also be more than happy to discuss other Mono technologies that I've worked on such as MonoDevelop, MonoTouch, Mono for Android, ASP.NET MVC, and the use of Mono in games.

MonoDevelop Tips will Resume in May

In early February I started writing a series of MonoDevelop Tips, and after a solid run of a couple of months, I found it difficult to keep up with the challenging Mon-Tues-Weds-Thu-Fri schedule I originally set for myself, and had to take a break to catch up with all the other things I need to do. I'm building up a buffer of new posts, and I'll resume posting tips in May, on a Mon-Weds-Fri schedule. Now that MonoDevelop 2.6 beta 2 is out, I'll also start covering some of the new features in 2.6.

Please go back and read the past tips in case you missed any, and rate your favourites — comments and ratings encourage me to keep doing this.

MonoDevelop Tips: Navigate to Line in File

In an earlier post, I introduced the Navigate To dialog, which allows quickly navigating to any file or type in the solution. It has a couple more useful capabilities which are not immediately obvious.

Firstly, it's possible to go directly to a specific line in the selected file by typing a colon followed by the line number. As soon as the colon is typed, the list will narrow down to only contain files, not types or members. When you hit Enter to navigate to the file, you will be taken directly to the specified line, if it's valid.

Navigating to a specific line

This also works in the more specialized Go to File dialog.

Another hidden feature is that it's possible to access several options by clicking on the search icon in the search box.

The Navigate To options

The options that constrain the list's contents are fairly obvious. Disabling "complex matching" makes the searching faster but makes the fuzzy/acronym matching poorer.

MonoDevelop Tips: Document Outline Pad

One of my favourite pads in MonoDevelop is the document outline pad, which provides an overview of the current document and a way to jump quickly to any part of it. I like to keep it autohidden on the left side of the MonoDevelop window, so that I can quickly bring it up. You can show it using the View->Pads->Document Outline menu item, and change its position and docking to fit your workspace layout.

The document outline paf

Clicking on an item in the Document Outline pad will select or focus that item in the document. Outlines are shown for C# source, the GTK# GUI designer, XML, HTML, T4, ASP.NET, and more.

MonoDevelop Tips: Navigation History

MonoDevelop keeps track of your navigation history, like a web browser. If you jump to another file or another position inside the same file, you can easily navigate back. This is particularly useful combined with MonoDevelop's other code navigation features that make it easy to jump around your code, such as the "Go to definition" command and the Navigate To dialog. The Navigation History can get you back to wherever you were before.

To navigate back, use Ctrl-Alt-Left on Window or Linux, or Cmd-Opt-Left on a Mac. To navigate forward, use Ctrl-Alt-Right on Window or Linux, or Cmd-Opt-Right on a Mac.

These commands are also found in the Search menu, along with the Navigation History list, which shows a list of the last fifteen locations, and allows you to jump directly to any of them. Internally it keeps more history than this, but menu space is limited.

The Navigation History menu

The commands are also found in the Navigation toolbar.

The Navigation History toolbar

Navigation points are created whenever you use a command that navigates directly to something, such as opening a file, going to a definition, and so on. If you manually move the caret around a file and stay in one area for more than about 10 seconds, it may also log a navigation point there.

Pages

Subscribe to Journal