Hey yall<br><br>Seems IronRuby objects do not yet work with WPF
databinding. One approach to a workaround is to emit a wrapper type
that defines CLR properties. When WPF calls the getter/setter the call
is forwarded ot the contained contained ruby object. This will allow
defining business objects in ruby and databing them to the UI. <br>
<br>This might be useful to thers, so here is my approach. The first
part is C# code that defines a type given a list of property names. The
second part is ruby code that creates a wrapper instance for a given
ruby object and caches the type so that you dont generate a type for
each element in an array..<br>
<br>The C# code to generate a type:<br><br>using System;<br>using System.Collections.Generic;<br>using System.Linq;<br>using System.Text;<br>using System.Reflection;<br>using System.Reflection.Emit;<br><br>namespace GenerateType<br>

{<br><br>&nbsp;&nbsp;&nbsp; public class TypeGenerator<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public delegate object GetPropertyDelegate(string propertyName);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public delegate object SetPropertyDelegate(string propertyName, object value);<br><br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static Type Generate(string className, List&lt;string&gt; properties)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AssemblyName asmName = new AssemblyName(&quot;BindingTypes&quot;);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AssemblyBuilder asmBuilder = AppDomain.CurrentDomain.<div id=":11m" class="ArwC7c ckChnd">
DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule(&quot;Types&quot;);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TypeBuilder typeBuilder = modBuilder.DefineType(className,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TypeAttributes.Public |<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TypeAttributes.Class |<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TypeAttributes.AutoClass |<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TypeAttributes.AnsiClass |<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TypeAttributes.BeforeFieldInit |<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TypeAttributes.AutoLayout);<br>

<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FieldBuilder getFieldBuilder = typeBuilder.DefineField(&quot;OnGet&quot;, typeof(GetPropertyDelegate), FieldAttributes.Public);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FieldBuilder setFieldBuilder = typeBuilder.DefineField(&quot;OnSet&quot;, typeof(SetPropertyDelegate), FieldAttributes.Public);<br>

<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MethodAttributes getSetAttr =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MethodAttributes.Public | MethodAttributes.SpecialName |<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MethodAttributes.HideBySig;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach (string propertyName in properties)<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PropertyBuilder propBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.None, typeof(object), new Type[] {});<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MethodBuilder getter =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typeBuilder.DefineMethod(&quot;get_&quot; + propertyName,<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getSetAttr,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typeof(string),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Type.EmptyTypes);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ILGenerator ilGen = getter.GetILGenerator();<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ilGen.Emit(OpCodes.Ldarg_0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ilGen.Emit(OpCodes.Ldfld, getFieldBuilder);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ilGen.Emit(OpCodes.Ldstr, propertyName);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ilGen.Emit(OpCodes.Callvirt, typeof(GetPropertyDelegate).GetMethod(&quot;Invoke&quot;));<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ilGen.Emit(OpCodes.Ret);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Define the &quot;set&quot; accessor method for CustomerName.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MethodBuilder setter =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typeBuilder.DefineMethod(&quot;set_&quot; + propertyName,<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getSetAttr,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; null,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new Type[] { typeof(string) });<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ilGen = setter.GetILGenerator();<br>

<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ilGen.Emit(OpCodes.Ldarg_0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ilGen.Emit(OpCodes.Ldfld, setFieldBuilder);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ilGen.Emit(OpCodes.Ldstr, propertyName);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ilGen.Emit(OpCodes.Ldarg_1);<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ilGen.Emit(OpCodes.Callvirt, typeof(SetPropertyDelegate).GetMethod(&quot;Invoke&quot;));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ilGen.Emit(OpCodes.Pop);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ilGen.Emit(OpCodes.Ret);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Last, we must map the two methods created above to our PropertyBuilder to <br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // their corresponding behaviors, &quot;get&quot; and &quot;set&quot; respectively. <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; propBuilder.SetGetMethod(getter);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; propBuilder.SetSetMethod(setter);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return typeBuilder.CreateType();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>}<br><br><br>And here is the ruby code to generate the wrapper type<br><br>require &#39;mscorlib&#39;<br>require &#39;C:\Documents and Settings\Josh\My Documents\Visual Studio 2008\Projects\GenerateType\GenerateType\bin\Release\GenerateType.dll&#39;<br>

require &#39;PresentationFramework, Version=<a href="http://3.0.0.0/" target="_blank">3.0.0.0</a>,Culture=neutral, PublicKeyToken=31bf3856ad364e35&#39;<br>require &#39;PresentationCore, Version=<a href="http://3.0.0.0/" target="_blank">3.0.0.0</a>, Culture=neutral, PublicKeyToken=31bf3856ad364e35&#39;<br>

require &#39;WindowsBase, Version=<a href="http://3.0.0.0/" target="_blank">3.0.0.0</a>, Culture=neutral, PublicKeyToken=31bf3856ad364e35&#39;<br><br>include System<br>include System::Collections::Generic<br>include GenerateType<br>
include System::Collections::ObjectModel<br>
include System::Windows<br>include System::Windows::Controls<br>include System::Windows::Data<br>include System::Windows::Input<br><br>class WrapperGenerator<br>&nbsp; def initialize<br>&nbsp;&nbsp;&nbsp; @wrapper_cache = {}<br>&nbsp; end<br><br>

&nbsp; def wrap(ruby_object)<br>&nbsp;&nbsp;&nbsp; if ruby_object.is_a? Array<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ruby_object.map {|o| wrap(o) }<br>&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cache(ruby_object) unless cached(ruby_object)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wrapper_class = cached(ruby_object)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wrapper_class.new(ruby_object)<br>

&nbsp;&nbsp;&nbsp; end<br>&nbsp; end<br><br>&nbsp; def invalidate<br>&nbsp;&nbsp;&nbsp; @wrapper_cache.clear<br>&nbsp; end<br>private<br>&nbsp; def cached(object)<br>&nbsp;&nbsp;&nbsp; @wrapper_cache[<a href="http://object.class.name/" target="_blank">object.class.name</a>]<br>&nbsp; end<br>
&nbsp; <br>&nbsp; def cache(object)<br>
&nbsp;&nbsp;&nbsp; @wrapper_cache[<a href="http://object.class.name/" target="_blank">object.class.name</a>] = generate_wrapper(object)<br>&nbsp; end<br><br>&nbsp; def generate_wrapper(object)<br>&nbsp;&nbsp;&nbsp; wrapper_name = &quot;#{<a href="http://object.class.name/" target="_blank">object.class.name</a>}Wrapper&quot;<br>

&nbsp;&nbsp;&nbsp; properties = List.of(System::String).new<br><br>&nbsp;&nbsp;&nbsp; (object.methods - Object.instance_methods).each {|m| properties.add m.to_s}<br><br>&nbsp;&nbsp;&nbsp; wrapper_base_type = TypeGenerator.generate(&quot;#{wrapper_name}Base&quot;, properties)<br>

&nbsp;&nbsp;&nbsp; base_instance = Activator.create_instance wrapper_base_type<br><br>&nbsp;&nbsp;&nbsp; eval &lt;&lt;EOS<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class #{wrapper_name} &lt; base_instance.class<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; def initialize(original)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.on_get = lambda do |prop|<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; original.send prop<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.on_set = lambda do |prop, val|<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; original.send &quot;\#{prop}=&quot;, val<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return #{wrapper_name} # return the class<br>

EOS<br>&nbsp;&nbsp;&nbsp; <br>&nbsp; end<br>end<br><br>class Person <br>&nbsp; attr_accessor :first_name, :last_name<br><br>&nbsp; def initialize(first_name, last_name)<br>&nbsp;&nbsp;&nbsp; @first_name, @last_name = first_name, last_name<br>&nbsp; end<br><br>&nbsp; def full_name<br>

&nbsp;&nbsp;&nbsp; &quot;#{last_name}, #{first_name}&quot;<br>&nbsp; end<br>end<br><br><br># A sample UI<br><br>people = []<br><br>10.times { |n| people &lt;&lt; Person.new(&quot;John #{n}&quot;, &quot;Smith&quot;) }<br><br>wrapper = WrapperGenerator.new<br>

<br>w = Window.new<br>combo = ComboBox.new<br>combo.items_source = wrapper.wrap(people) # wrap people objects<br>combo.display_member_path = &quot;full_name&quot;<br>combo.margin = 20<br>w.content = combo<br><br>Application.new.run w</div>