Navigation


Markus on Development and Publishing

This is Markus Egger's professional blog, which covers topics such as development, publishing, and business in general. As the publisher of CoDe and CoDe Focus magazines, and as the President and Chief Software Architect of EPS Software Corp., Markus shares his insights and opinions on this blog.

Content Area Footer

Sunday, April 11, 2010
A Real-World DynamicObject Example in C#

The other day I had to solve an interesting problem and it turned out that C# 4.0’s dynamic features came in very handy. In fact, I thought the way we used the features was so interesting, I wanted to share it with it.

The basic situation was this: I was tasked with building a UI editor that is part of an product we are currently building, This allows the user to create custom forms and UIs and such. The fields that go on the forms (as well as all the labels and other elements) are data bound. For instance, you could drop a first-name field on a UI and that would result in a label and a textbox. The textbox is data bound to the data element that represents the current record’s first name field. The label itself is also data bound so the caption of the label is driven by meta data and can be translated or generally set by the user.

The trouble was that when a UI is in design mode in the editor, the data context may or may not be available (more likely not). Now this is a real bummer, because a label with a data bound caption that doesn’t find its data source has an empty caption, which means it is invisible. As you can imagine, the design experience was sub-optimal.

So how can we provide some sort of data context that works no matter what? We need a context that not just has the capability to show something useful to the user, but it needs to be able to act as just about any binding expression. For instance, let’s say we have the following element on a form:

<TextBlock Text="{Binding Label_FirstName}" />

This requires that the current data element has a Label_FirstName property this can bind to. And since this expression is user-definable, that would mean you’d need an object that has any and every conceivable property name. That’s not going to happen.

What we did instead is we derived a new object from the new DynamicObject class. This is a special class that behaves in a dynamic way. Most importantly for our scenario, it as a TryGetMember() method. This method gets called every time someone tries to access a member on the object. For instance, of someone accesses x.HelloWorld, instead of going straight to a HelloWorld property, the TryGetMember() method gets called, and one of its parameters indicates what the name of the desired member is (“HelloWorld” in this case). We can use this method to then take control of the operation and return a value rather than letting the operation pass to a real member (which wouldn’t exist in our case).

Here is a simplified version of the example we are using:

public class BindingFaker : DynamicObject
{
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        var nameParts = binder.Name.Split('_');
        if (nameParts.Length == 3) result = nameParts[1];
        else if (nameParts.Length == 2) result = nameParts[1];
        else if (nameParts.Length == 1) result = nameParts[0];
        else result = binder.Name;

        result = "{" + result + "}";

        return true;
    }
}

As you can see, the binder parameter provides information about what member is being accessed. In our case, we take over all operations and simply check the member name. We apply a little bit of logic to the member name and then simply echo it back. (For instance, a member name of “Label_FirstName” would echo back “{FirstName}”). This way, we always provide some meaningful value being returned, no matter what the binding expression tries to access. (Note: Our real world implementation is a little more sophisticated since sometimes meta-data may be available and if so, we use it).

So now, we can simply always attach this object as the DataContext of the object that’s being designed and the binding expressions will always go to the TryGetMember() method which returns whatever we want it to return so the user sees something meaningful.

This has worked out very well. Doing this without dynamic features would have been very difficult. Using DynamicObject on the other hand was trivial and only a few lines of code. Cool! :-)



Posted @ 9:31 PM by Egger, Markus (markus@code-magazine.com) -
Comments (1)




Comments:

RE: A Real-World DynamicObject Example in C#
Thursday, July 22, 2010 4:26 AM by wedding - tombupliy@gmail.com

Those are very historical images. Thank you for posting this very interesting and informative post.




Post a Comment:

Comment Title (required)

Your Name (optional)

Your Email (optional)

Your Web Site (optional)

Your Comment (required)

 

 

 

 

 

 

 



My Twitter Status


    follow me on Twitter  


    Geo Caching
    Profile for MarkusEgger

    Syndication RSS 2.0 RSS 2.0

    All My Blogs:
    My personal blogs:
    Dev and Publishing Dev and Publishing
    Travel and Internat. Living Travel and Internat. Living
    Other blogs I contribute to:
    Milos Blog (US) Milos Blog (US)
    VFPConv. Dev Blog (US) VFPConv. Dev Blog (US)
    VFPConv. Dev Blog (DE) VFPConv. Dev Blog (DE)

     

    Blog Archives
    All Blog Posts

    2010
        August (2)
        July (1)
        June (1)
        April (3)
        March (1)
        February (5)
        January (1)
    2009
        October (4)
        September (2)
        August (1)
        July (1)
        May (4)
        April (6)
        February (1)
        January (1)
    2008
        December (3)
        November (11)
        October (8)
        September (1)
        July (1)
        June (3)
        May (3)
        April (6)
        March (6)
        February (4)
    2007
        December (1)
        November (1)
        October (5)
        September (1)
        August (1)
        July (6)
        June (3)
        May (3)
        April (1)
        March (2)
        January (2)
    2006
        December (3)
        November (4)
        October (1)
        September (2)
        August (2)
        July (4)
        June (1)
        May (2)
        April (10)
        March (2)
        February (3)
        January (1)
    2005
        December (6)
        November (7)
        October (6)
        September (8)
        August (10)
        July (6)
        June (9)

     

     

     

    This Blog is powered by MilosTM Collaboration Components.