看到部落格園有篇文章談到“使用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
【本文首發于: 搜尋研發部官方部落格】 http://stblog.baidu-tech.com/?p=100 【 關注百度技術沙龍】
轉載于:https://blog.51cto.com/baidutech/743790