WPF中DataTemplate该写在哪儿
直接写在
Resources里最稳妥,比如
Window.Resources或
UserControl.Resources。不推荐硬塞进
ContentControl.Template或
ItemsControl.ItemTemplate的内联位置——改起来费劲,复用不了,XAML还容易臃肿。
如果模板要跨多个控件复用,就提成
ResourceDictionary单独文件,再用
MergedDictionaries引入。注意路径写法:
Source="pack://application:,,,/YourAssembly;component/Themes/MyTemplates.xaml",漏了
component或拼错大小写都会静默失效。
DataTemplate绑定不到数据?检查DataType和DataContext
DataType不是类型名字符串,而是带命名空间的完整类型名,比如
{x:Type local:Person},其中local必须已在XAML顶部用
xmlns:local="clr-namespace:MyApp.Models"声明。写成
Person或
MyApp.Models.Person都不行。
更常见的问题是
DataContext没传到位:
ItemsControl.ItemsSource设了集合,但集合元素本身没正确实现
INotifyPropertyChanged,界面不会响应属性变更 模板内用了
RelativeSource找祖先控件的
DataContext,结果祖先压根没设——这时候绑定会静默失败,输出窗口里能看到
System.Windows.Data Error日志 用
StaticResource引用模板时,模板定义必须出现在引用位置之前(XAML自上而下解析)
如何动态切换DataTemplate(比如按状态选不同UI)
靠
DataTemplateSelector。写一个继承
DataTemplateSelector的类,重写
SelectTemplate方法,根据
item内容返回不同
DataTemplate对象。
关键点:
模板对象必须是已加载的资源,不能临时new DataTemplate()——WPF不支持运行时构造完整模板 在
SelectTemplate里别做耗时操作,它可能被高频调用(比如滚动列表时) 如果需要响应属性变化触发模板切换,得手动调用
ItemsControl.ItemContainerGenerator.StatusChanged或刷新
ItemsSource
示例片段:
<local:StatusTemplateSelector x:Key="MySelector" />,然后在
ItemsControl上设
ItemTemplateSelector="{StaticResource MySelector}"。
用代码创建DataTemplate太麻烦?优先用XAML + FindResource
纯C#构造
DataTemplate极其繁琐:得用
FrameworkElementFactory(已标记为
Obsolete),还要手动设
VisualTree、
Triggers,连绑定都得靠
SetBinding逐个配。现在官方推荐路径是——写好XAML模板,用
FindResource取出来复用。
比如:
var template = (DataTemplate)this.FindResource("PersonTemplate");,再赋给myContentControl.ContentTemplate = template;。这样既保持可维护性,又避免运行时解析错误。
真正绕不开代码的场景只有两个:模板内容完全动态生成(如列数不定的表格),或需根据运行时配置拼接模板字符串——这时建议用
XamlReader.Parse,但务必校验输入,否则XAML注入风险真实存在。
