A discussion about Rich Internet Applications, and user experience focusing on architecture, design patterns and methodologies.

Tuesday, November 9, 2010

Dynamic Entity Binding

Silverlight provides a powerful binding mechanism to allow a comprehensive solution for data transport and validation.  Unfortunately, this binding relies on a hard coded model for implementation.  In the scenario where the schema of the data entity is not known at compile time, there is nothing provided out of the box.

I have come up with a fairly generic solution that stores data in a dictionary type construct with validation  and localization support, leveraging Silverlight’s exiting binding infrastructure.

For this blog post, I will focus on the core classes for binding support, with subsequent updates for validation and localization.

The main class for this solution is the DynamicEntity.

The data and metadata are stored in a private dictionary, and a public indexer overload provides public access directly to the data (necessary for the binding declaration). The key thing to understand here is that binding on a dictionary type object requires collection change notification, not property change notification, to work.  I have included property change notification for additional flexibility.  The field class contains the field metadata and the value.

    public class Field
    {
        public FieldMetadata Metadata { get; set; }
        
        public object Value { get; set; }
    }


The field metadata contains properties with meta-information about the field, including name, description, and type.  In a future blog post, I will add validators and localization support as well as describe a label control that functions like the SDK Label.



To use this, we can expose the entity as a property in our ViewModel as follows:



public DynamicEntity Entity { get; set; }
        public MainPage()
        {
            
            Entity = new DynamicEntity();
            FieldMetadata field = new FieldMetadata(typeof(string), "FirstName", "FirstNameLabel" , "FirstNameDescription", typeof(Strings));
            field
                .AddValidator("FirstName", new RequiredValidator("FirstNameRequired"))
                .AddValidator("FirstName", new StringLengthValidator("FirstNameStringLength") { MaximumLength = 40 });
            
            Entity.AddField(field, "Carlos");              
            
            DataContext = this;
            this.InitializeComponent();
        }


… and then we bind as follows:



<TextBox x:Name="textBox" Text="{Binding Entity[FirstName], Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnNotifyDataErrors=True}"/>


I will be posting the source code with all the features (validation, localization) on my codeplex site with the last post in this series.

Friday, June 4, 2010

Leak proof event bus using MEF

I’ve been trying to implement my own “Event Bus” (Pub/Sub pattern) using MEF since it seems natural to export an event, or a delegate.  The problem is that a reference on one object to a delegate on another object could cause memory leaks.  (See Weak Events in C# by Daniel Grunwald   http://bit.ly/chKG7W).

Following Daniel Grunwald’s article, I considered all the possibilities there and finally settled on “Weak Reference to Delegate”.  This is simply an Event wrapper that uses a weak reference to store each delegate. 

        List<WeakReference> handlers = new List<WeakReference>();
        public event EventHandler<TEventArgs> Event
        {
            add
            {
                handlers.RemoveAll(wr => !wr.IsAlive);
                handlers.Add(new WeakReference(value));
            }
            remove
            {
                    handlers.RemoveAll(wr =>
                                           {
                                               EventHandler<TEventArgs> target = (EventHandler<TEventArgs>)wr.Target;
                                               return target == null || target == value;
                                           });
            }
        }


As Daniel states though, this alone will cause the delegates to be garbage collected, even though the delegate’s source is still referenced.  The delegate’s source must maintain a hard reference to the delegate itself.  In terms of the pub/sub pattern, the subscriber needs to create a reference to the event handler that is being added to the published event.



private WeakReferenceToDelegate<EventArgs<TParam>> _eventReference = new WeakReferenceToDelegate<EventArgs<TParam>>();
EventHandler<EventArgs<TParam>> _handler
Register()
{
    _handler = Handler;
    _eventReference.Event += _handler;
}
private void Handler(object sender, EventArgs<object> e)
{
    ...
}


That is a lot of obscure code to subscribe to an event, so I set about encapsulating the logic.  The resulting code looks like this:



    public class Publisher
    {
        [Export("PublisherNotification")]
        public Notification<Object> Notification { get; set; }
        public Publisher()
        {
            Notification = new Notification<Object>();
        }
        public void PublishNotification()
        {
            Notification.Publish(null);
        }
    }
    public class Subscriber
    {
        private NotificationSubscription<object> _subscription;
        public Subscriber()
        {
            _subscription = new NotificationSubscription<object>("PublisherNotification", Handler);
        }
        private void Handler(object sender, EventArgs<object> e)
        {
            //do something
        }
    }


The notification object is just a facade for WeakReferenceToDelegate.



    public class Notification<TParam>
    {
        private WeakReferenceToDelegate<EventArgs<TParam>> _eventReference = new WeakReferenceToDelegate<EventArgs<TParam>>();
        internal void Subscribe(EventHandler<EventArgs<TParam>> handler)
        {
            _eventReference.Event += handler;
        }
        public void Publish(object source, TParam param)
        {
            _eventReference.FireEvent(source, new EventArgs<TParam>(param));
        }
    }


 



The notification subscription object wraps the “Listener” logic.



 



    public class NotificationSubscription<TParam>
    {
        private EventHandler<EventArgs<TParam>> _handler;
        public NotificationSubscription(string notificationName, EventHandler<EventArgs<TParam>> handler)
        {
            _handler = handler;
            Notification<TParam> notification = ModuleService.Container.GetExportedValue<Notification<TParam>>(notificationName);
            notification.Subscribe(_handler);
           
        }
    }


If I tried to import the Notification object, a memory leak would occur.  I suspect that satisfying imports on an object creates a reference to that object which resulted in the subscription object living longer than the subscriber.  I used manual composition instead but that means I needed to locate the CompositionContainer.  I used a static reference to the container for this (ModuleService.Container).



The listener keeps a hard reference to the delegate.  The listener should only be referenced by the delegate’s source to prevent memory leaks. 



I have checked all of this in to a new version of the my Refract library that is dependent on MEF.   You can find it http://refract.codeplex.com/.  This particular code is in $\Code\Trunk\Refract\Refract\Event along with an implementation of a published function called “Query”.

Monday, April 19, 2010

ViewModel and Design-Time Data

I have been mulling over different approaches for implementing the ViewModel (MVVM) pattern and feel that I’m close to a solution that I’m happy with.  I have the following criteria:

  • View First.  I don’t like the idea of the ViewModel having even the slightest dependency on the view.  That way I can easily isolate it and test it.  The view I have no intention of (unit) testing as it will not have any code.
  • MEF only.  For now, I’m focusing on lean and simple.  I was a big fan of Prism, but I’m shying away from big, frameworks that force me down a path.  I’m liking light-weight utility libraries better.  Sure I have to write more code, but I have full control and much more flexibility to adapt the solution to the requirements.
  • Blendable design data.  The first thing that excited me about WPF/e (original Silverlight code name) was the improvement in Designer/Developer work flow.  Giving the designer a better experience and more control over the interface design is definitely an advantage.

I originally thought it would be nice to have the ViewModel discoverable at design time (as discussed in this article by John Papa, but I had trouble getting the ViewModel to be registered by MEF at design time.  I then explored the new ViewModel support in Expression Blend, and I liked it.

In my experience the Designer typically creates the prototypes, hands them off to the developer and then needs to go back to update the design.  This has always been a painful process, especially in an ASP.Net web forms application. 

  1. The prototypes come as a Visio file, or html web pages. 
  2. The developer needs to spend a lot of time transforming this into an ASP.Net web page, and falls short of recreating the exact design. 
  3. The designer then has a really hard time working with the ASP.Net source and updates the original prototype. 
  4. The Developer needs to update the application page to match the new prototypes

The result is friction between the two teams, and a lot of UI bugs generated by QA.  Ideally, the developer and designer work should with the same files and do not conflict with each.  In the world of Silverlight 4, the following is possible:

  • The designer creates the interface in Expression Blend and attaches sample data to the forms
  • The developer adds functionality to the forms and Visual Studio, only modifying the bindings in the presentation layer
  • The designer can continue to make modifications to the presentation layer in Expression Blend even after the developer has worked with it

One of the challenges I faced working with MEF was troubleshooting import failures.  I managed to resolve all except the timing for import of the composition container itself in the base view.  I use this to resolve a viewmodel by name:

public static class ExportProviderExtensions

    {
        public static object GetExport(this ExportProvider provider, string typeName)
        {
            return GetExport(provider, typeName, typeName);

}

}

 



And then use this in the base View class:



    public class View : Page 
    {
        private string _viewModelName;
        public string ViewModelName
        {
            get { return _viewModelName; }
            set
            {
                _viewModelName = value;
                ViewModel = ContainerLocator.Container.GetExport(ViewModelName) as ViewModelBase;
            }
        }
        public ViewModelBase ViewModel
        {
            get { return (ViewModelBase)DataContext; }
            set { DataContext = value; }
        }
    }


The ContainerLocator just stores the CompositionContainer in a static property.



The sample view model simply creates some data:



    [Export]
    public class MainViewModel : ViewModelBase
    {
        public Collection<Thing> List { get; set; }
        public MainViewModel()
        {
            List = new Collection<Thing>()
                       {new Thing {Value = "One"}, new Thing {Value = "Two"}, new Thing {Value = "Three"}};
            RaisePropertyChanged("List");
        }
    }


The view model name is set in the view xaml:



<rf:View x:Class="Silverlight4.Composite.MainView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:rf="clr-namespace:Refract.Views;assembly=Refract"  
    ViewModelName="Silverlight4.Composite.MainViewModel">


I could not get this to work in the designer, because the designer host did not properly register exported types in the assembly, but I realized that it is not necessary.  I can use Expression Blend to create a data source from a class.  Point the wizard to the view model and voilĂ , design time data that is customizable by the designer:



image



<Silverlight4_Composite:MainViewModel 
        Data="Aliquam cras duis integer" IsInDesignMode="True" >    
        <Silverlight4_Composite:MainViewModel.List>
                <Silverlight4_Composite:Thing Value="Curabitur maecenas phasellus class aenean"/>
                <Silverlight4_Composite:Thing Value="Praesent nunc curae nam"/>
                <Silverlight4_Composite:Thing Value="Quisque vivamus accumsan"/>    
        </Silverlight4_Composite:MainViewModel.List>
</Silverlight4_Composite:MainViewModel> 


Blend sets the data context on the first control you bind to, but I moved it to the root of the xaml:



<rf:View …
    d:DataContext="{d:DesignData /SampleData/MainViewModelSampleData.xaml}" …



The result (In Blend):



image



… and in the browser:



image

Saturday, April 17, 2010

Dictionarys in XAML

Short and simple post about how to declare and bind to a custom dictionary in Silverlight 4.  I had trouble finding a solid example of this since it has been properly introduced in the full release of Silverlight this past week.

Essentially I derived from Dictionary<String,String> and called it CustomDictionary within the application project.  Add a namespace declaration called local for the project and then:

<UserControl.Resources>
<local:CustomDictionary x:Name="dictionary">
<
sys:String x:Key="One">1</sys:String>
<
sys:String x:Key="Two">2</sys:String>
<
sys:String x:Key="Three">3</sys:String>
</
local:CustomDictionary >
</
UserControl.Resources>

<
Grid>
<
TextBlock Text="{Binding Source={StaticResource dictionary}, Path=[One]}"></TextBlock>
</Grid>



Quite simple really.  You bind to the dictionary resource and specify the key as the path.



Why do this?  I really like the idea of creating a dynamic and blendable ViewModel locator (thanks John Papa http://bit.ly/b11pUB) and I wanted to try my hand at doing this myself without the converter.



I’m planning on posting a blog on using MEF for composition and DI soon.  I think for smaller projects, it makes sense to keep it simple.  For larger projects, Unity might make more sense.

About Me

My photo
Toronto, ON, Canada
I am a technical architect at Navantis, with over 12 years experience in IT. I have been involved in various projects, including a Hospital information system called CCIS for which my team received the 2007 Tech-Net innovation award. I have been working with Silverlight since beta 1, and am very keen on practically applying this technology and WPF to line of business applications.