如何在c#代码中构建DataTemplate?

90

我正在尝试为winform interop构建一个下拉列表,并且我正在使用代码创建下拉列表。 但是,我在获取基于我指定的DataTemplate绑定数据时遇到问题。

我缺少什么?

drpCreditCardNumberWpf = new ComboBox();  
DataTemplate cardLayout = new DataTemplate {DataType = typeof (CreditCardPayment)};   
StackPanel sp = new StackPanel
{
    Orientation = System.Windows.Controls.Orientation.Vertical
};   

TextBlock cardHolder = new TextBlock {ToolTip = "Card Holder Name"};
cardHolder.SetBinding(TextBlock.TextProperty, "BillToName");
sp.Children.Add(cardHolder);

TextBlock cardNumber = new TextBlock {ToolTip = "Credit Card Number"};
cardNumber.SetBinding(TextBlock.TextProperty, "SafeNumber");
sp.Children.Add(cardNumber);

TextBlock notes = new TextBlock {ToolTip = "Notes"};
notes.SetBinding(TextBlock.TextProperty, "Notes");
sp.Children.Add(notes);

cardLayout.Resources.Add(sp, null);

drpCreditCardNumberWpf.ItemTemplate = cardLayout;

4
请注意,虽然这些答案在当时是正确的,但目前推荐的以编程方式创建模板的方法是使用XamlReader类的Load方法从字符串或内存流中加载XAML。 - Sheridan
3个回答

161

假设您已经为 drpCreditCardNumberWpf 设置了 ItemsSource 等...

//create the data template
DataTemplate cardLayout = new DataTemplate();
cardLayout.DataType = typeof(CreditCardPayment);

//set up the stack panel
FrameworkElementFactory spFactory = new FrameworkElementFactory(typeof(StackPanel));
spFactory.Name = "myComboFactory";
spFactory.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);

//set up the card holder textblock
FrameworkElementFactory cardHolder = new FrameworkElementFactory(typeof(TextBlock));
cardHolder.SetBinding(TextBlock.TextProperty, new Binding("BillToName"));
cardHolder.SetValue(TextBlock.ToolTipProperty, "Card Holder Name");
spFactory.AppendChild(cardHolder);

//set up the card number textblock
FrameworkElementFactory cardNumber = new FrameworkElementFactory(typeof(TextBlock));
cardNumber.SetBinding(TextBlock.TextProperty, new Binding("SafeNumber"));
cardNumber.SetValue(TextBlock.ToolTipProperty, "Credit Card Number");
spFactory.AppendChild(cardNumber);

//set up the notes textblock
FrameworkElementFactory notes = new FrameworkElementFactory(typeof(TextBlock));
notes.SetBinding(TextBlock.TextProperty, new Binding("Notes"));
notes.SetValue(TextBlock.ToolTipProperty, "Notes");
spFactory.AppendChild(notes);

//set the visual tree of the data template
cardLayout.VisualTree = spFactory;

//set the item template to be our shiny new data template
drpCreditCardNumberWpf.ItemTemplate = cardLayout;

您可以使用我设置在上的ToolTip的相同方法来设置其他属性,例如边距。


2
在Silverlight 4中,FrameworkElementFactory类不存在。我也不想使用XAML.Load。有没有其他方法可以解决这个问题? - curiosity
2
针对Silverlight 4/5... 参考:http://blogs.msdn.com/b/scmorris/archive/2008/04/14/defining-silverlight-datagrid-columns-at-runtime.aspx - Nordes
3
参见:http://www.codeproject.com/Articles/444371/Creating-WPF-Data-Templates-in-Code-The-Right-Way - Daniel Hilgarth

6
完整版
var ms = new MemoryStream(Encoding.UTF8.GetBytes(@"<DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
                                                                 xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""                                                                             
                                                                 xmlns:c=""clr-namespace:MyApp.Converters;assembly=MyApp"">
        <DataTemplate.Resources>
            <c:MyConverter x:Key=""MyConverter""/>
        </DataTemplate.Resources>
        <TextBlock Text=""{Binding ., Converter={StaticResource MyConverter}}""/>
      </DataTemplate>"));
var template = (DataTemplate)XamlReader.Load(ms);

var cb = new ComboBox { };
//Set the data template
cb.ItemTemplate = template;

1
注意 - XamlReader.Load 不接受事件处理程序。 - Mikhail Orlov
这是我需要使用的解决方案,因为如果您使用编程方式(设置可视树等),它将无法正确解析所有元素名称绑定。 - toeb

0

嗯,实际上我们还有另一种方法,如果你不喜欢那些FrameworkElementFactory的东西,你会真的很喜欢它。

我认为它只是对自然代码进行了微小的更改,也就是声明一个UserControl并将您的控件放入其中,然后使用一个FrameworkElementFactory来调用UserControl

简单的演示代码(使用F#):

let buildView()=StackPanel()
//Build it with natural code
type MyView()=inherit UserControl(Content=buildView())
let factory=FrameworkElementFactory(typeof<MyView>)
let template=DataTemplate(VisualTree=factory)
let list=ItemsControl(ItemsSource=makeData(),ItemTemplate=template)

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