My Experiment:
Can I move over to Ruby as my primary programming language when developing WPF and Silverlight applications? I have been playing around with what it would mean to use Ruby to write my ViewModels, which would also make it easier to incorporate models using Ruby.
My next few blog posts will revolve around some things I have learned with this experiment. As described in my disclaimer, I am a bit of a hack when it comes to Ruby. There are probably better ways to do what I am suggesting. If so, feel free to call me out. I won’t mind. Seriously.
INotifyPropertyChanged
So, if I am going to write ViewModels in Ruby, the first thing is to implement INotifyPropertyChanged, which is an interface that includes one event. It is used by WPF and SIlverlight to update the UI when something changes:
public interface INotifyPropertyChanged { event PropertyChangedEventHandler PropertyChanged; }
But… how do I define events from Ruby? It’s not like Ruby has events as a language feature. As it turns out, in C# for every event (Foo), two methods are created: add_Foo() and remove_Foo() which are mapped from Foo += handler and Foo –= handler. So, to get the PropertyChanged event methods implemented in Ruby, I just implement the add_ and remove_ methods. Following is the full implementation of a Ruby class that implements INotifyPropertyChanged:
class TestClassinclude System::ComponentModel::INotifyPropertyChangeddef initialize@handlers = []enddef add_PropertyChanged(handler)@handlers << handlerenddef remove_PropertyChanged(handler)@handlers.delete(handler)enddef PropertyChanged(sender, args)@handlers.each { |h| h.invoke(sender, args) }endend
So, with that, the Ruby code can send an event to .Net code by calling PropertyChanged().
But… Seriously… Lets Metaprogram, Shall We?
The previous code is kind of awkward. Every time you want to declare an event, you have to write this code?
Of course not. This is Ruby. We have metaprogramming! Lets create some code to generate this code. I talked with a ruby developer friend of mine, Toby Tripp, and he helped me get to this mixin code that will generate the methods for you:
module DotNetEventsmodule ClassMethodsdef declare_event( *events )events.each do |event|define_handler_methods( event )endenddef define_handler_methods( event )event_name = event.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }class_eval <<-EOSdef handlers( event_name )@event_handlers ||= Hash.new@event_handlers[ event_name ] ||= []enddef add_#{event_name}( handler )handlers( :#{event_name} ) << handlerenddef remove_#{event_name}( handler )handlers( :#{event_name} ).delete handlerenddef #{event_name}( sender, args )handlers( :#{event_name} ).each do |handler|handler.invoke sender, argsendendEOSendenddef self.included(receiver)receiver.extend ClassMethodsendend
Now that we have this declare_event method, we can use it to define events. Just implement the interface, and declare the event:
class TestClassinclude DotNetEventsinclude System::ComponentModel::INotifyPropertyChangeddeclare_event :PropertyChangedend
Note that I have, indeed, tested this with WPF. The WPF system properly hooks up the event and when the Ruby code fires it, the UI gets updated.
From here, I can build my ViewModel base class in Ruby. Some things to solve still: making notification of PropertyChanged events easy, commands, data binding, ViewModel hookups, etc. But, at least, I am on my way :)
Tags: MVVM, Ruby, Silverlight, WPF
Very interesting Brian. While my Ruby-fu is weak, I have been toying with this very idea for some time. I´ll will follow this series with much interest.
keep up the good work!
I’m curious to see how far you can get with IronRuby and Silverlight.
In the beginning of the year, I had a similar experiment with IronPython and Silverlight. Thanks to clrtypes.py I was able to get further that I had in the past. However, ultimately I reached a dead end when trying to get custom ValueConverters (IValueConverter) to work.
See this thread: http://lists.ironpython.com/pipermail/users-ironpython.com/2010-January/011991.html
And this follow-up: http://lists.ironpython.com/pipermail/users-ironpython.com/2010-February/012102.html
I’m curious to see how far you can get with IronRuby and Silverlight. In the beginning of the year, I had a similar experiment with IronPython and Silverlight. Thanks to clrtypes.py I was able to get further that I had in the past. However, ultimately I reached a dead end when trying to get custom ValueConverters (IValueConverter) to work. See this thread: http://lists.ironpython.com/pipermail/users-ironpython.com/2010-January/011991.html And this follow-up: http://lists.ironpython.com/pipermail/users-ironpython.com/2010-February/012102.html