[IronPython] Monkey-patching CLR types
Dino Viehland
dinov at microsoft.com
Tue Feb 16 04:18:01 CET 2010
If you strongly type handler to a delegate type IronPython should
convert the function to the delegate type on the call. I had meant to
write "EventHandler<HtmlEventArgs>" in my original sample code but somehow
I ended up using the Python syntax EventHandler[HtmlEventArgs] :)
Yeah, the comment's write, I'm wrong http://msdn.microsoft.com/en-us/library/2sk3x8a7(VS.71).aspx
lists op_AdditionAssignment but not InPlaceAdd.
> -----Original Message-----
> From: users-bounces at lists.ironpython.com [mailto:users-
> bounces at lists.ironpython.com] On Behalf Of Jimmy Schementi
> Sent: Monday, February 15, 2010 7:08 PM
> To: Discussion of IronPython
> Subject: Re: [IronPython] Monkey-patching CLR types
>
> Thanks Dino!
>
> I've got something to at least compile, but I'm getting the error
> "ArgumentTypeException: unsupported operand type(s) for +=:
> 'PythonBrowserEvent' and 'function'". OK, makes sense, it's not finding
> InPlaceAdd(Python.Runtime.Method), right? Since I can't link against
> IronPython, what type should I use instead of Python.Runtime.Method?
> System.Dynamic.IDynamicMetaObjectProvider, as that's the only DLR
> interface that Method implements? If so, then I'm not sure how to
> convert it to an Action<object, HtmlEventArgs>.
>
> Also, should I be using "op_AdditionAssignment" instead of InPlaceAdd?
> The usage in ReflectedEvent.cs
> (http://ironpython.codeplex.com/sourcecontrol/changeset/view/63991?proj
> ectName=IronPython#384571) seems to say that.
>
> If it helps, here's what I have so far:
>
> public static class HtmlElementExtension {
> [SpecialName]
> public static object GetBoundMember(HtmlElement element, string
> name) {
> object propertyValue = element.GetProperty(name);
> // No way to tell if a property actually exists, so best we
> can do
> // do is check if it's null ...
> if (propertyValue == null) {
> return new PythonBrowserEvent(element, name);
> }
> return propertyValue;
> }
> }
>
> public class PythonBrowserEvent {
> private readonly HtmlElement _element;
> private readonly string _event;
>
> internal PythonBrowserEvent(HtmlElement element, string
> eventStr) {
> _element = element;
> _event = eventStr;
> }
>
> [SpecialName]
> public object InPlaceAdd(object handler) {
> _element.AttachEvent(_event,
> new EventHandler<HtmlEventArgs>((Action<object,
> HtmlEventArgs>)handler));
> return null;
> }
> }
>
> > -----Original Message-----
> > From: users-bounces at lists.ironpython.com [mailto:users-
> > bounces at lists.ironpython.com] On Behalf Of Dino Viehland
> > Sent: Sunday, February 14, 2010 4:58 PM
> > To: Discussion of IronPython
> > Subject: Re: [IronPython] Monkey-patching CLR types
> >
> > You can define an extension property that gets/sets a value which
> supports in
> > place addition / subtraction. Something like this:
> >
> > [assembly: ExtensionType(typeof(HtmlElement),
> > typeof(HtmlElementExtension))]
> > public static class HtmlElementExtension {
> > [SpecialName, PropertyMethod]
> > public static MyEvent Getonclick(HtmlElement element) {
> > return new MyEvent(element);
> > }
> > [SpecialName, PropertyMethod]
> > public static void Setonclick(HtmlElement element, object
> value) {
> > // You could return a value from InPlaceAdd and validate it
> > here
> > // to report an error on a direct assignment - this is what
> > // ReflectedEvent does in IronPython.
> > }
> > }
> >
> > public class MyEvent {
> > private readonly HtmlElement _element;
> > public MyEvent(HtmlElement element) {
> > _element = element;
> > }
> > [SpecialName]
> > public object InPlaceAdd(EventHandler[HtmlEventArgs]
> handler) {
> > _element.AttachEvent("onclick", handler);
> > return null;
> > }
> > // also needs InPlaceSubtract
> > }
> >
> > -----Original Message-----
> > From: users-bounces at lists.ironpython.com [mailto:users-
> > bounces at lists.ironpython.com] On Behalf Of Jimmy Schementi
> > Sent: Sunday, February 14, 2010 2:06 PM
> > To: Discussion of IronPython
> > Subject: [IronPython] Monkey-patching CLR types
> >
> > (Yes, I'm asking a question this time =P)
> >
> > I want to know my options for adding functionality to an existing CLR
> type.
> > Specifically I want to make hooking DOM events cleaner: in
> Silverlight today
> > you cannot hook DOM events with the standard += syntax that
> IronPython uses
> > for CLR events:
> >
> > object.onclick += foo
> >
> > Instead you must do this:
> >
> > object.AttachEvent("onclick", EventHandler[HtmlEventArgs](foo))
> >
> > In IronRuby I fixed that by just monkey-patching
> > System.Windows.Browser.HtmlObject, but in IronPython I cannot monkey-
> patch
> > built-in types. However, I do something similar with accessing DOM
> properties
> > (instead of element.GetProperty("innerHTML") it's just
> element.innerHTML)
> > with DLR's ExtensionType, which is the same way IronPython exposes
> special
> > methods on CLR types as well:
> >
> > [assembly: ExtensionType(typeof(HtmlElement),
> > typeof(HtmlElementExtension))]
> > public static class HtmlElementExtension {
> > [SpecialName]
> > public static object GetBoundMember(HtmlElement element,
> string name)
> > {
> > return element.GetProperty(name);
> > }
> > }
> >
> > But after looking through Python's Binder and the DLR's ActionBinder
> for how
> > they use ExtensionTypes, I couldn't get a definitive answer on how to
> capture
> > an method call plus an operator. Any ideas?
> >
> > ~Jimmy
> >
> > _______________________________________________
> > Users mailing list
> > Users at lists.ironpython.com
> > http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
> > _______________________________________________
> > Users mailing list
> > Users at lists.ironpython.com
> > http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
>
> _______________________________________________
> Users mailing list
> Users at lists.ironpython.com
> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
More information about the Ironpython-users
mailing list