看到博客园有篇文章谈到“使用C#编程的方式创建DataTemplate数据模板”(原文地址), 博主的做法是创建一个FrameworkElementFactory对象,设置好后将其设置为DataTemplate对象的VisualTree属 性。我认为此方法有待商榷,盖因查阅MSDN,发现FrameworkElementFactory类的介绍页面上有一段备注:
(http://msdn.microsoft.com/zh-cn/library/system.windows.frameworkelementfactory.aspx)
备注:通过此类以编程方式创建模板这种方式已被否决,这些模板是 FrameworkTemplate(如 ControlTemplate 或 DataTemplate)的子类;使用此类创建模板时,并非所有模板功能都可用。以编程方式创建模板的推荐方式是:使用 XamlReader 类的 Load 方法从字符串或内存流中加载 XAML。
因此,正确的做法似乎是编程创建一段XAML代码并且使用XamlReader类的Load方法将其构造成为实例对象。下面代码展示了这一做法(为了演示,数据绑定操作全部由C#代码而不是xaml完成):
下面代码完成一个小程序,该程序可以输入名字和昵称,将之加入到ListBox列表中,如果选中ListBox某一项,输入框内容会实时更新,也可以实时修改名字和昵称。首先使用XAML描述出程序界面:
MainWindow.xaml:
-
-
<label>姓名</label>
-
-
<label>昵称</label>
-
-
<button>增加</button>
下面将TextBox、ListBox的数据源全部绑定到我们自己的数据结构上,先定义一个NickName类,实现INotifyPropertyChanged接口:
MainWindow.xaml.cs:
- public class NickName: INotifyPropertyChanged
- {
- public NickName() : this( “Name”, “Nick” ) { }
- public NickName( string name, string nick )
- {
-
namename_ = name; nicknick_ = nick;
- }
-
- public event PropertyChangedEventHandler PropertyChanged;
- private void FireEvent( string propertyName )
- {
- if( PropertyChanged != null )
- PropertyChanged( this, new PropertyChangedEventArgs( propertyName ) );
- }
-
- private string name_;
- public string Name
- {
- get { return name_; }
- set{
-
if( name_ == value ) return;
-
name_ = value;
- FireEvent( “Name” );
- }
- }
-
- private string nick_;
- public string Nick
- {
- get { return nick_; }
- set{
-
if( nick_ == value ) return;
-
nick_ = value;
- FireEvent( “Nick” );
- }
- }
- }
下面代码在内存中使用XAML定义了一个DataTemplate,并将之实例化,完成了ListBox的数据绑定操作:
MainWindow.xaml.cs:
- public partial class MainWindow: Window
- {
-
//ObservableCollection<>集合实现了INotifyCollectionChanged接口
-
public ObservableCollection nickNames_ = new ObservableCollection();
-
- public MainWindow()
- {
- InitializeComponent();
- DoDataBinding();
- //点击“增加”按钮时将TextBox中的内容增加到nickNames_容器中
- //由于ListBox已经绑定到nickNames_,这将导致ListBox显示内容的更新
-
btnAdd_.Click += ( o, e ) => {
- nickNames_.Add( new NickName() );
- };
- }
-
- private void DoDataBinding()
- {
- //设定总体的数据上下文,它将影响DockPanel里面所有控件
-
dockPanel_.DataContext = nickNames_;
-
- //将ListBox绑定到nickNames_,并设定同步更新当前Item属性
- lstBox_.SetBinding( ListBox.ItemsSourceProperty, string.Empty );
-
lstBox_.IsSynchronizedWithCurrentItem = true;
-
- //内存中动态生成一个XAML,描述了一个DataTemplate
-
XNamespace ns = “http://schemas.microsoft.com/winfx/2006/xaml/presentation”;
-
XElement xDataTemplate =
-
new XElement( ns + “DataTemplate”, new XAttribute( “xmlns”, “http://schemas.microsoft.com/winfx/2006/xaml/presentation” ),
- new XElement( ns + “TextBlock”,
-
new XElement( ns + “TextBlock”, new XAttribute( “Width”, “100″ ), new XAttribute( “Text”, “{Binding Path=Name}” ) ),
-
new XElement( ns + “TextBlock”, new XAttribute( “Width”, “100″ ), new XAttribute( “Text”, “{Binding Path=Nick}” ) )
- )
- );
- //将内存中的XAML实例化成为DataTemplate对象,并赋值给
- //ListBox的ItemTemplate属性,完成数据绑定
-
XmlReader xr = xDataTemplate.CreateReader();
-
DataTemplate dataTemplate = XamlReader.Load( xr ) as DataTemplate;
-
lstBox_.ItemTemplate = dataTemplate;
- //将两个TextBox分别绑定到当前Item的Name和Nick属性上
- txtBoxName_.SetBinding( TextBox.TextProperty, “Name” );
- txtBoxNick_.SetBinding( TextBox.TextProperty, “Nick” );
- }
-
- }
通过上述代码,已经成功使用C#代码创建了DataTemplate数据模板,并完成了这个小程序:
由于刚开始学习WPF,代码中难免有不当之处,恳请牛人指正。
By liuxiaobo
本文转自百度技术51CTO博客,原文链接:http://blog.51cto.com/baidutech/743790,如需转载请自行联系原作者