【问题标题】:Create DataTemplate in codebehind在后面的代码中创建 DataTemplate
【发布时间】:2011-07-25 04:36:13
【问题描述】:

如何以编程方式向数据模板添加控件?

例如。下面我创建了 TextBlock 和 DataTemplate。

TextBlock text = new TextBlock();
DataTemplate template = new DataTemplate();

现在我需要将 TextBlock 添加到 DataTemplate。如何做到这一点?

我知道还有其他方法可以在后面的代码中添加数据模板 1. 在 XAML 中创建一个数据模板并将其加载到后面的代码中 2.使用XamlParser创建和添加

但我需要按照我在示例中展示的方式进行操作。

需要帮助。

【问题讨论】:

    标签: c# dynamic datatemplate code-behind


    【解决方案1】:

    虽然Archedius's method 有效,但官方已弃用它,而是推荐以编程方式创建模板的方法是使用 XamlReader 类的 Load 方法从字符串或内存流中加载 XAML...

    public DataTemplate Create(Type type)
    {
        StringReader stringReader = new StringReader(
        @"<DataTemplate 
            xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""> 
                <" + type.Name + @" Text=""{Binding " + ShowColumn + @"}""/> 
            </DataTemplate>");
        XmlReader xmlReader = XmlReader.Create(stringReader);
        return XamlReader.Load(xmlReader) as DataTemplate;
    }
    

    官方线路取自msdn:http://msdn.microsoft.com/en-us/library/system.windows.frameworkelementfactory.aspx

    Fredrik Hedblad 帖子中的代码示例:Problems with XamlReader generating DataTemplate

    【讨论】:

    • 在 System.Windows.Markup NOT System.Xaml 中使用 XamlReader
    • 其他选项可能已过时,这是一个非常不方便的方法,不仅它几乎不提供静态错误检查,而且产生的错误消息是神秘的(例如意外字符0x20 在第 5 行第 27 位),此外这也意味着您无权访问项目的资源。恕我直言,远离这个,但最简单的模板。
    【解决方案2】:

    我知道这是一种变通方法,但我在代码项目 (http://www.codeproject.com/Tips/808808/Create-Data-and-Control-Templates-using-Delegates) 中发布了一个提示,允许您使用委托创建数据模板。 例如:

    TemplateGenerator.CreateDataTemplate(() => new TextBox());
    

    这足以创建一个创建新文本框的数据模板。如果你也想要一个绑定,它可以这样写:

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

    TemplateGenerator 的代码如下:

    /// <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;
      }
    }
    

    它也有一个 ControlTemplates 的方法。

    【讨论】:

    • 这是迄今为止最好的答案,也适用于复杂的 DataTemplates - 其他两个答案都失败了
    【解决方案3】:

    您必须首先声明一个 DataTemplate:

    DataTemplate template = new DataTemplate { DataType = typeof(< Type of the object the template refers>) };
    

    然后这样声明一个像StackPanel这样的布局面板

    FrameworkElementFactory stackPanelFactory = new FrameworkElementFactory(typeof(StackPanel));
    stackPanelFactory.SetValue(StackPanel.OrientationProperty, Orientation.Vertical);
    

    最后附上 TextBlock 块:

    FrameworkElementFactory title = new FrameworkElementFactory(typeof(TextBlock));
    title.SetBinding(TextBlock.TextProperty, new Binding("< name of your binding >"));
    stackPanelFactory.AppendChild(title);
    

    为了显示以这种方式创建的 StackPanel,您必须将其附加到 VisualTree:

    template.VisualTree = stackPanelFactory;
    

    希望对您有所帮助! :)

    【讨论】:

      猜你喜欢
      • 2019-05-05
      • 1970-01-01
      • 2020-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-14
      相关资源
      最近更新 更多