Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
WPF Dynamic DataTemplates
using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace WpfApplication8
{
public class AutoTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item == null) return null;
var type = item.GetType();
var scrollViewerFactory = new FrameworkElementFactory(typeof(ScrollViewer));
scrollViewerFactory.SetValue(ScrollViewer.VerticalScrollBarVisibilityProperty, ScrollBarVisibility.Auto);
scrollViewerFactory.SetValue(ScrollViewer.HorizontalScrollBarVisibilityProperty, ScrollBarVisibility.Disabled);
scrollViewerFactory.AppendChild(GetPanelFactory(item));
var template = new DataTemplate(type)
{
VisualTree = scrollViewerFactory
};
return template;
}
FrameworkElementFactory GetPanelFactory(object item, string parentPath = "")
{
var type = item.GetType();
var panelFactory = new FrameworkElementFactory(typeof(StackPanel));
panelFactory.SetValue(Grid.IsSharedSizeScopeProperty, true);
var propsInOrder = from prop in type.GetProperties()
where prop.CanRead
let display = prop.GetAttribute<DisplayAttribute>()
orderby display != null ? display.GetOrder() : null
select new
{
prop.Name,
prop.PropertyType,
Property = prop,
DisplayAttribute = display
};
foreach (var prop in propsInOrder)
{
var gridFactory = new FrameworkElementFactory(typeof(Grid));
var labelColumn = new FrameworkElementFactory(typeof(ColumnDefinition));
labelColumn.SetValue(ColumnDefinition.SharedSizeGroupProperty, "label");
var valueColumn = new FrameworkElementFactory(typeof(ColumnDefinition));
valueColumn.SetValue(ColumnDefinition.SharedSizeGroupProperty, "value");
gridFactory.AppendChild(labelColumn);
gridFactory.AppendChild(valueColumn);
var labelTextBlockFactory = new FrameworkElementFactory(typeof(TextBlock));
labelTextBlockFactory.SetValue(TextBlock.MarginProperty, new Thickness(5));
labelTextBlockFactory.SetValue(TextBlock.OpacityProperty, 0.5);
labelTextBlockFactory.SetValue(Grid.ColumnProperty, 0);
string label = null;
if (prop.DisplayAttribute != null)
{
label = prop.DisplayAttribute.Name;
if (!String.IsNullOrWhiteSpace(prop.DisplayAttribute.Description))
{
labelTextBlockFactory.SetValue(TextBlock.ToolTipProperty, prop.DisplayAttribute.Description);
}
}
if (label == null)
{
var displayName = prop.Property.GetAttribute<DisplayNameAttribute>();
if (displayName != null)
{
label = displayName.DisplayName;
}
}
labelTextBlockFactory.SetValue(TextBlock.TextProperty, label ?? prop.Name);
gridFactory.AppendChild(labelTextBlockFactory);
FrameworkElementFactory valueFactory;
if (prop.PropertyType.IsValueType || prop.PropertyType == typeof(String))
{
valueFactory = new FrameworkElementFactory(typeof(TextBlock));
valueFactory.SetBinding(TextBlock.TextProperty, new Binding(parentPath + "." + prop.Name));
valueFactory.SetValue(TextBlock.MarginProperty, new Thickness(5));
}
else if (typeof(IEnumerable).IsAssignableFrom(prop.PropertyType))
{
valueFactory = new FrameworkElementFactory(typeof(ItemsControl));
valueFactory.SetValue(ItemsControl.ItemTemplateSelectorProperty, this);
valueFactory.SetValue(ItemsControl.AlternationCountProperty, 2);
valueFactory.SetBinding(ItemsControl.ItemsSourceProperty, new Binding(parentPath + "." + prop.Name));
}
else
{
valueFactory = GetPanelFactory(prop.Property.GetValue(item, new object[0]), prop.Name);
}
valueFactory.SetValue(Grid.ColumnProperty, 1);
gridFactory.AppendChild(valueFactory);
panelFactory.AppendChild(gridFactory);
}
return panelFactory;
}
}
public static class PropertyInfoExtensions
{
public static T GetAttribute<T>(this System.Reflection.PropertyInfo prop)
{
return prop.GetCustomAttributes(typeof(T), true).Cast<T>().FirstOrDefault();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment