【问题标题】:How to create DataTemplate from UserControl instance?如何从 UserControl 实例创建 DataTemplate?
【发布时间】:2012-11-17 12:08:51
【问题描述】:

问题

基本上我想做以下事情,但似乎我做不到:

UserControl myControl = new UserControl();
DataTemplate template = new DataTemplate(myControl);

问题:是否可以从 UserControl 实例构造 DataTemplate?如果没有,还有其他可能的解决方案吗?


真正的问题

我正在做一个项目,其中大多数 UI 视图都是简单的静态 Word 类文档(例如,一些文本字段,可能还有一些图像,没什么花哨的)。因为从事这个项目的大多数人都不是程序员,所以我们为 UI 生成设计了非常简单的内部标记语言。简单视图的标记示例如下:

First name: [Person.FirstName]
Last name: [Person.LastName]
Address: [Person.Address.Street], [Person.Address.City]

现在这些模板在运行时加载,并基于它们创建用户控件。在这种情况下,将创建一个用户控件,它只包含几个堆栈面板和文本块,因此生成的控件看起来有点像文本文档。 XAML 等效项类似于:

<StackPanel>
    <StackPanel Orientation="Horizontal">
        <TextBlock Text="First name: "/>
        <TextBlock Text={Binding Person.FirstName}
    </StackPanel>
    <StackPanel>
        ...
    </StackPanel>
    ...
</StackPanel>

然后,我开始实现对列表的支持,但想不出如何做到这一点。理论上它很简单,我想出了以下语法(+ XAML 等价物):

[List Customers]
First name: [Person.FirstName]
Last name: [Person.LastName]
Address: [Person.Address.Street], [Person.Address.City]
[EndList]

->

<StackPanel>
    <ItemsControl ItemsSource="{Binding Customers}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                [Insert code from previous XAML example here]
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</StackPanel>

但我不能这样做,因为我似乎无法直接从 UserControl instance 构造 DataTemplate。如果我的 UserControl 是 types 就没有问题,但它们不是。

一种可能的解决方案是我可以将 ItemsControl.Items 直接绑定到 UserControls 列表(而不是绑定到 ItemsSource 和 ItemTemplate),但是出于几个原因,这在我们的案例中是次优的。我愿意先尝试其他一些解决方案!

更新

为了澄清:我所拥有的只是 UserControl 类的普通实例,其中包含我需要的内容。例如

UserControl control = new UserControl();
var panel = new StackPanel();
panel.Children.Add(...);
panel.Children.Add(...);
control.Content = panel;
// How to use that control as ItemTemplate for ItemsControl?
// It seems that it is not possible directly but I want to
// know what my options are.

我没有针对它的类,因为我是在运行时构建它,并且我不想通过发出 IL 代码来动态创建新类型,因为这太痛苦了。

【问题讨论】:

    标签: c# wpf user-controls datatemplate


    【解决方案1】:

    从 Code behind 创建数据模板如下:

    FrameworkElementFactory factory = new FrameworkElementFactory(MyUserControl.GetType());
    DataTemplate dt = new DataTemplate();
    dt.VisualTree = factory;
    
    yourItemsControlInstance.ItemTemplate = dt;
    

    数据模板是要在运行时构建的控件的定义,即使用 ElementFactory 构建的方式。您不希望 ItemsControl 中的每个项目都使用相同的 UserControl 实例。

    【讨论】:

    • 是的,我知道这一点,但正如我在问题中提到的那样,没有任何类型可以传递给 FEF。当我有 UserControl 实例(克隆、提取信息以创建类型等)时,我正在寻找一些方法来做类似的事情
    • 您要提取信息来创建类型吗?你有你的用户控件的类型信息来创建一个实例。如果您执行上述操作,请说明缺少哪些信息?你的意思是你在编译时不知道类型?您可以使用 GetType() 获取运行时实例的类型。
    • 好吧,看来我还不够清楚。我已经更新了这个问题。基本上,我所拥有的只是 UserControl 类的普通实例,而不是单独的类型。
    【解决方案2】:

    啊,我现在明白你的问题了。我认为没有简单的方法(一两行代码)从 UserControl 实例创建数据模板。

    但要解决您的问题,我看到了两个方向:

    1. 在创建用户控件时,创建一个数据模板并使用它。使用嵌套的 FrameworkElementFactories 会很麻烦。我从来没有这样做过,MSDN 文档说与 Xaml 中的数据模板相比,您可能会遇到一些您无法做到的限制。但如果它很简单,它必须是可行的。 Sacha Barber 曾经有一篇 codeproject 文章,您可以将其用作指导(如果需要)。
    2. 您将 UserControl 的创建打包到一个名为 private UserControl createMyUserControl(){} 的方法中

    然后做这样的事情:

        ItemsControl itemsControl = new ItemsControl();
        foreach (var customer in Customers) 
        {
           var usercontrol = createMyUserControl(...);
           usercontrol.DataContext = customer;
           itemsControl.Items.Add(usercontrol);
        }
    

    在我看来,第二个选项不太优雅,所以我会先检查选项 1。

    WPF: How to create Styles in code/and magical Content (see section at the end for extensive sample of a DataTemplate in Code behind)

    【讨论】:

    • 第一个选项听起来不错,我会试一试。谢谢!我已经考虑过第二种选择,但正如你所说,它远没有那么优雅。
    【解决方案3】:

    我认为您可以将UserControl 替换为ContentControl。 只需将ContentControl 的内容设置为所需的模板,并将其用作 ItemsControl 的 ItemTemplate。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-15
      • 2019-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-23
      • 2021-09-21
      • 2014-08-03
      相关资源
      最近更新 更多