如何通过编程创建一个带内容的数据模板?

21

我想在运行时通过代码实现以下操作:

<DataTemplate x:Key="lightGreenRectangle">
        <Rectangle Fill="LightGreen"/>
    </DataTemplate>

到目前为止,我已经得到了:

public DataTemplate GetColouredRectangleInDataTemplate(Color colour)
{
    DataTemplate dataTemplate = new dataTemplate();

    return dataTemplate;
}

求助?我知道这不是最优雅的控件样式方式,但我想要指定一个颜色的组件具有一个名为“PointTemplate”的类型为DataTemplate的属性。


1
如果您想为控件设置样式,应使用ControlTemplate,而Datatemplate用于以特定方式显示数据。回到您的问题,您想为什么设置颜色? - MBen
像这样的东西对你有用吗?DataTemplate asd = new DataTemplate(); asd.DataType = typeof(Rectangle); asd.VisualTree.SetValue(Rectangle.FillProperty, Brushes.Green); - peer
请注意,尽管这些答案在当时是正确的,但当前推荐的以编程方式创建模板的方法是使用XamlReader类的Load方法从字符串或内存流中加载XAML。 - Sheridan
2个回答

29
如果由于某种原因您需要以编程方式创建DataTemplate,则可以执行以下操作:
XAML:
<Grid x:Name="myGrid">
    <ContentControl ContentTemplate="{DynamicResource lightGreenRectangle}" />
</Grid>

在你的代码中的某个地方:

    public static DataTemplate CreateRectangleDataTemplate()
    {
        var rectangleFactory = new FrameworkElementFactory(typeof(Rectangle));
        rectangleFactory.SetValue(Shape.FillProperty, new SolidColorBrush(System.Windows.Media.Colors.LightGreen));

        return new DataTemplate
                   {
                       VisualTree = rectangleFactory,
                   };
    }

    public static void AddRectangleTemplateToResources(FrameworkElement element)
    {
        element.Resources.Add("lightGreenRectangle", CreateRectangleDataTemplate());
    }

那么您只需要将DataTemplate添加到ResourceDictionary中,以便可以使用它。例如,在代码后台:

    public MainWindow()
    {
        InitializeComponent();
        AddRectangleTemplateToResources(myGrid);
    }

希望这能有所帮助!


这对Silverlight来说可能吗? - Shaun Rowan
没事了,找到了:http://blogs.msdn.com/b/scmorris/archive/2008/04/14/defining-silverlight-datagrid-columns-at-runtime.aspx - Shaun Rowan
出现了这个错误:找不到名为'lightGreenRectangle'的资源。资源名称区分大小写。 - Mohsen
需要添加 rectangleFactory.Name = "lightGreenRectangle";,我相信。已经进行了编辑以将其放入其中。 - vapcguy
请注意,现在以编程方式生成DataTemplate的首选方法是直接从字符串解析XAML:DataTemplate template = XamlReader.Parse(xamlString, parserContext) as DataTemplate; - Sheridan

10

使用以下辅助类:

/// <summary>
/// Class that helps the creation of control and data templates by using delegates.
/// </summary>
public static class TemplateGenerator
{
  private sealed class _TemplateGeneratorControl:
    ContentControl
  {
    internal static readonly DependencyProperty FactoryProperty = DependencyProperty.Register("Factory", typeof(Func<object>), typeof(_TemplateGeneratorControl), new PropertyMetadata(null, _FactoryChanged));

    private static void _FactoryChanged(DependencyObject instance, DependencyPropertyChangedEventArgs args)
    {
      var control = (_TemplateGeneratorControl)instance;
      var factory = (Func<object>)args.NewValue;
      control.Content = factory();
    }
  }

  /// <summary>
  /// Creates a data-template that uses the given delegate to create new instances.
  /// </summary>
  public static DataTemplate CreateDataTemplate(Func<object> factory)
  {
    if (factory == null)
      throw new ArgumentNullException("factory");

    var frameworkElementFactory = new FrameworkElementFactory(typeof(_TemplateGeneratorControl));
    frameworkElementFactory.SetValue(_TemplateGeneratorControl.FactoryProperty, factory);

    var dataTemplate = new DataTemplate(typeof(DependencyObject));
    dataTemplate.VisualTree = frameworkElementFactory;
    return dataTemplate;
  }

  /// <summary>
  /// Creates a control-template that uses the given delegate to create new instances.
  /// </summary>
  public static ControlTemplate CreateControlTemplate(Type controlType, Func<object> factory)
  {
    if (controlType == null)
      throw new ArgumentNullException("controlType");

    if (factory == null)
      throw new ArgumentNullException("factory");

    var frameworkElementFactory = new FrameworkElementFactory(typeof(_TemplateGeneratorControl));
    frameworkElementFactory.SetValue(_TemplateGeneratorControl.FactoryProperty, factory);

    var controlTemplate = new ControlTemplate(controlType);
    controlTemplate.VisualTree = frameworkElementFactory;
    return controlTemplate;
  }
}

你可以像这样创建一个数据模板:

DataTemplate template = 
  TemplateGenerator.CreateDataTemplate
  (
    () =>
    {
      var result = new TextBox()
      result.SetBinding(TextBox.TextProperty, "BindingPathHere");
      return result;
    }
  );

您可以自由使用任何代码来创建控件,就像直接创建控件一样,而无需使用任何数据模板。

有关更多信息,请参见此代码项目中的提示:http://www.codeproject.com/Tips/808808/Create-Data-and-Control-Templates-using-Delegates


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接