Click here to Skip to main content
15,867,686 members
Articles / Silverlight / Silverlight5

Implicit DataTemplate in Silverlight 4 Composite UI – Get Ready for Silverlight 5 (Part II)

Rate me:
Please Sign up or sign in to vote.
4.20/5 (2 votes)
24 May 2011CPOL2 min read 14K  
How I implemented the ContentControl implicit data-template using the ImplicitContentTemplateBehavior attached behavior

In this post, I'll show how I implemented the ContentControl implicit data-template using the ImplicitContentTemplateBehavior attached behavior.

But first, let's talk a bit about how WPF searches for an implicit data template, given a content, so we can mimic that behavior in Silverlight.

Having a ContentControl with a Content set to an instance of type Circle, WPF looks at the ControlControl.ItemTemplate. In case that one is missing, and there is no ItemTemplateSelector, it changes strategy, and tries finding a Data Template by traversing upward the logical-tree, looking inside each element resource dictionary for a template which has the type of Circle (or base classes – but not interfaces!) as the key (implicitly or explicitly set).

First, it looks at the ContentControl resources, if not found, it goes one level up, and searches at the parent level until one is found or until it reaches the root element, then finishes by searching at the Application level resources.

So now that we have an idea, let's look at the ImplicitContentTemplateBehavior attached behavior.

C#
public class ImplicitContentTemplateBehavior : Behavior<ContentControl>
{
    protected override void OnAttached()
    {
        var binding = new Binding("Content")
        {
            Mode = BindingMode.OneWay,
            Source = AssociatedObject,
            Converter = new DataTemplateConverter(AssociatedObject),
        };
 
        BindingOperations.SetBinding
        (AssociatedObject, ContentControl.ContentTemplateProperty, binding);
            
        base.OnAttached();
    }
 
    private class DataTemplateConverter : IValueConverter
    {
        private ContentControl _contentControl;
 
        public DataTemplateConverter(ContentControl contentControl)
        {
            this._contentControl = contentControl;
        }
 
        #region IValueConverter Members
 
        public object Convert(object value, Type targetType, 
        object parameter, System.Globalization.CultureInfo culture)
        {
            return ImplicitDataTemplateResolver.Resolve(_contentControl);
        }
 
        public object ConvertBack(object value, Type targetType, 
        object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotSupportedException();
        }
 
        #endregion
    }
}

As you can see, I've implemented the OnAttached method of the attached behavior by creating a Binding extension to bind the ContentControl (the associated object) Content Template property with the implicit data template, using a value converter which actually searches for the data template upward the tree.

Whenever the Content property is changing, the converter Convert method is called. Here, I'm using a helper class to find the data template.

Let's look at the ImplicitDataTemplateResolver helper:

C#
internal static class ImplicitDataTemplateResolver
{
    internal static DataTemplate Resolve(ContentPresenter contentPresenter)
    {
        return Resolve(contentPresenter, contentPresenter.Content);
    }
 
    internal static DataTemplate Resolve(ContentControl contentControl)
    {
        return Resolve(contentControl, contentControl.Content);
    }
 
    private static DataTemplate Resolve(FrameworkElement contentElement, object content)
    {
        DataTemplate resolvedDataTemplate = null;
        if (content != null)
        {
            resolvedDataTemplate = InternalResolve(contentElement, content.GetType().FullName);
        }
 
        return resolvedDataTemplate;
    }
 
    private static DataTemplate InternalResolve(FrameworkElement element, string contentTypeName)
    {
        if (element == null)
        {
            return TryFindDataTemplate(Application.Current.Resources, contentTypeName);
        }
 
        var dataTemplate = TryFindDataTemplate(element.Resources, contentTypeName);
        if (dataTemplate == null)
        {
            var parent = VisualTreeHelper.GetParent(element) as FrameworkElement;
            dataTemplate = InternalResolve(parent, contentTypeName);
        }
 
        return dataTemplate;
    }
 
    private static DataTemplate TryFindDataTemplate
    (ResourceDictionary resourceDictionary, string contentTypeName)
    {
        DataTemplate dataTemplate = null;
        if (resourceDictionary.Contains(contentTypeName))
        {
            dataTemplate = resourceDictionary[contentTypeName] as DataTemplate;
        }
 
        return dataTemplate;
    }        
}

The Resolve static method, calls a Resolve private method with the new content. This calls the InternalResolve with the content full type name (I'm using this as a unique key since we can't use x:Type in Silverlight 4), which in turn, traverse upward the Visual Tree using the VisualTreeHelper helper class. In case a Data Template was found, it returns it. If not, keep searching up until reaching the root element. Then it looks at the Application resources as last resort.

Note: For simplicity, I didn't try to find Data Template defined for base classes, but feel free to add that if missing.

Here is the code of this sample.

In my next post, I'll show how I implemented the ImplicitItemTemplateBehavior attached behavior, which uses the same ImplicitDataTemplateResolver helper class, but with a different approach.

Stay tuned.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect CodeValue
Israel Israel
Tomer Shamam is a Software Architect and a UI Expert at CodeValue, the home of software experts, based in Israel (http://codevalue.net). Tomer is a speaker in Microsoft conferences and user groups, and in-house courses. Tomer has years of experience in software development, he holds a B.A degree in computer science, and his writings appear regularly in the Israeli MSDN Pulse, and other popular developer web sites such as CodePlex and The Code Project. About his thoughts and ideas you can read in his blog (http://blogs.microsoft.co.il/blogs/tomershamam).

Comments and Discussions

 
-- There are no messages in this forum --