WPF - How to programmatically materialize object to visual content?
Asked Answered
C

1

6

When you assign an object to a Content control it will materialize a Visual appropriate for that assigned object. Is there a programmatic way to achieve the same result? I would like to call a function in WPF with an object and get back a Visual, where the same logic is applied in generating the Visual as if you had supplied the object to a Content control instance.

For example, if I have a POCO object and assign it to a Content control and there happens to be an appropriate DataTemplate defined then it materializes that template to create the Visual. I would like my code to be able to take a POCO object and get back from WPF the Visual.

Any ideas?

Caustic answered 23/8, 2011 at 1:50 Comment(0)
L
9

Use DataTemplate.LoadContent(). Example:

DataTemplate dataTemplate = this.Resources["MyDataTemplate"] as DataTemplate;
FrameworkElement frameworkElement = dataTemplate.LoadContent() as FrameworkElement;
frameworkElement.DataContext = myPOCOInstance;

LayoutRoot.Children.Add(frameworkElement);

http://msdn.microsoft.com/en-us/library/system.windows.frameworktemplate.loadcontent.aspx

If you have a DataTemplate defined for all instances of a type (DataType={x:Type ...}, but no x:Key="...") then you can create content using the appropriate DataTemplate using the following static method. This method also emulates ContentControl by returning a TextBlock if no DataTemplate is found.

/// <summary>
/// Create content for an object based on a DataType scoped DataTemplate
/// </summary>
/// <param name="sourceObject">Object to create the content from</param>
/// <param name="resourceDictionary">ResourceDictionary to search for the DataTemplate</param>
/// <returns>Returns the root element of the content</returns>
public static FrameworkElement CreateFrameworkElementFromObject(object sourceObject, ResourceDictionary resourceDictionary)
{
    // Find a DataTemplate defined for the DataType
    DataTemplate dataTemplate = resourceDictionary[new DataTemplateKey(sourceObject.GetType())] as DataTemplate;
    if (dataTemplate != null)
    {
        // Load the content for the DataTemplate
        FrameworkElement frameworkElement = dataTemplate.LoadContent() as FrameworkElement;

        // Set the DataContext of the loaded content to the supplied object
        frameworkElement.DataContext = sourceObject;

        // Return the content
        return frameworkElement;
    }

    // Return a TextBlock if no DataTemplate is found for the source object data type
    TextBlock textBlock = new TextBlock();
    Binding binding = new Binding(String.Empty);
    binding.Source = sourceObject;
    textBlock.SetBinding(TextBlock.TextProperty, binding);
    return textBlock;
}
Lingonberry answered 23/8, 2011 at 4:9 Comment(4)
I want something that does exactly as the Content class does. i.e. follows the same logic as the Content control itself. You code is good and would be fine for the DataTemplate scenario. But there might not be a DataTemplate defined for my POCO.Caustic
If there is no matching DataTemplate then it falls back to creating a TextBlock and using ToString() on the POCO object to define the text.Caustic
Easy enough, I just updated the method to create a TextBox instead of returning null if no DataTemplate is found. FYI - ContentControl will display UIElement content as a UIElement, so don't use this method if you already have a UIElement as content.Lingonberry
The problem is the internal bindings don't work, all the control are unbound.Filial

© 2022 - 2024 — McMap. All rights reserved.