In this post, I want to discuss how I am loading the ViewModels into the View. When I write my Views, I like to use the tools I have available to me; Visual Studio and/or Expression Blend. This means that I want a Visual Studio project and I want to be able to use these tools to create new views quickly. The XAML files that define my views will still be backed by the obligatory auto-generated C# code, but this is where I want my C# code to end (for these experiments). I don’t want to write an more C# code than that (with one exception).
My ViewModels, however, will be written in Ruby. I will use RSpec to specify these ViewModels and I will use an editor other than Visual Studio to edit the code; mostly because Visual Studio does not have any tooling support for Ruby! At some point, my View world needs to converge with my ViewModel world.
To support this, I have written the only C# code that I intend to write in these experiments. It is a bootstrapper, if you will, to load Ruby ViewModels. It looks like this:
public class ViewModelLocator : DynamicObject { private readonly ScriptEngine engine; public ViewModelLocator() { engine = IronRuby.Ruby.CreateEngine(); engine.Runtime.LoadAssembly(typeof(INotifyPropertyChanged).Assembly); engine.Runtime.LoadAssembly(typeof(ICommand).Assembly); LoadAllViewModels(); } private void LoadAllViewModels() { Directory .EnumerateFiles("ViewModels", "*.rb").ToList() .ForEach(file => engine.ExecuteFile(file)); } public override bool TryGetMember(GetMemberBinder binder, out object result) { if (base.TryGetMember(binder, out result)) return true; result = FindViewModel(binder.Name); return result != null; } private object FindViewModel(string name) { return engine.Execute(name + ".new"); } }
This ViewModelLocator class exists for one reason: to generate Ruby ViewModels. It creates a Ruby script engine and pre-loads all the ViewModels when it is constructed. It then sits around, waiting to create new ViewModels for the View:
<StackPanel Orientation="Horizontal" DataContext="{Binding PersonViewModel, Source={StaticResource VMLocator}}"> <TextBlock Text="{Binding first}" Margin="5,0" /> <TextBlock Text="{Binding last}" Margin="5,0" /> </StackPanel>
In the XAML above, I am setting the DataContext of the StackPanel to create a new PersonViewModel (defined in Ruby). The binding references a ViewModelLocator as its source that was defined in App.xaml:
<Application.Resources> <IronRubyMVVM:ViewModelLocator x:Key="VMLocator" /> </Application.Resources>
A dead-simple ViewModel for illustration is defined in Ruby:
require File.dirname(__FILE__) + "/../RubyVM/ViewModelSupport" class PersonViewModel include ViewModelSupport declare_notifiable :first, :last def initialize @first = "Brian" @last = "Genisio" end end
You can see all the code in action from the snapshot of my project from which I wrote this post: I will be working on this project quite a bit after this post, so if you want to see what I have been working on, the code is always available.

Did you opt for C#-backed Views because you could not get 100% pure IronRuby Views to work?
In my IronPython/Silverlight experiments I didn’t even get as far as Views since I could not get ValueConverters to work…
I opted for C#-based Views because I want to use Expression Blend to say “New User Control” and there is now way that I know of to have it generate views with Ruby code-behind.
But, for my experiments to be completely successful, in my mind, I will need to write zero lines of C# code-behind in my views (except for my bootstrapper). By using the MVVM pattern, I believe that I can achieve this… but we’ll see :)
I haven’t even tried this in Silverlight yet, but I suspect my only modification to what I am doing will be to bind using the index operator: “{Binding [first]}” and “{Binding [last]}”.
I’ll blog about it more when I get there :)
Speaking of that, I’ll play with Ruby value converters and see if I can get it to work. I am guessing that your stumbling block with that was in creating the resource? Not sure how to do that yet :)