我有一个treeview,其中包含自定义类TreeviewItem项的itemsource。
我有一个TreeviewItem类型的属性SelectedTreeviewItemViewModel。
public TreeviewItem SelectedTreeviewItemViewModel //with INPC
我在窗口的其他地方有一个内容控件
<ContentControl Content="{Binding SelectedTreeviewItemViewModel}" />
使用datatemplate如下:
<DataTemplate DataType="{x:Type TreeviewItem}">
<uc:TreeviewCustomView />
</DataTemplate>
当我单击treeview的一个项目时,会触发事件SelectedItemChanged,并设置SelectedTreeviewItemViewModel,它强制contentcontrol刷新其内容。
逻辑很好,但是我注意到当我点击树视图中的新项目时,一些数据会更新但我不会进入用户控件的构造函数(uc:TreeviewCustomView)。
是否涉及某种虚拟化?我猜WPF缓存datatemplate;有没有什么办法可以强制WPF每次点击树视图项时从头开始重新创建用户控件(从而进入构造函数)?
使用绑定时,默认情况下会对TreeView进行虚拟化。如果将模式切换到VirtualizingPanel.VirtualizationMode =“Standard”而不是“Recycling”,则应调用构造函数。
这就是我的诀窍:
我创建了一个模板选择器,它基本上将模板包装在另一个模板中,强制创建一个新实例。请记住,这可能导致严重的性能问题!
在我的xaml中,我首先命名数据模板:
<DataTemplate x:Key="TreeviewItemTemplate" DataType="{x:Type TreeviewItem}">
<uc:TreeviewCustomView />
</DataTemplate>
然后我创建一个模板选择器如下:
public class TreeviewItemTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item == null)
{
return null;
}
var declaredDataTemplate = ((FrameworkElement)container).FindResource("TreeviewItemTemplate") as DataTemplate;
var wrappedDataTemplate = WrapDataTemplate(declaredDataTemplate );
return wrappedDataTemplate;
}
private static DataTemplate WrapDataTemplate(DataTemplate declaredDataTemplate)
{
var frameworkElementFactory = new FrameworkElementFactory(typeof(ContentPresenter));
frameworkElementFactory.SetValue(ContentPresenter.ContentTemplateProperty, declaredDataTemplate);
var dataTemplate = new DataTemplate();
dataTemplate.VisualTree = frameworkElementFactory;
return dataTemplate;
}
}
最后,我在内容控件上使用选择器:
<ContentControl Content="{Binding SelectedTreeviewItemViewModel }"
ContentTemplateSelector="{StaticResource TreeviewItemTemplateSelector }" />