我使用ResourceProvider
作为我的ResourceDictionaries的全局管理。我将新的ResourceDictionaries注册到ResourceProvider并为每个受影响的FrameworkElement引发一个事件。然后,FrameworkElement使用以下方法更新其资源:(我尝试了几种方法来解决此问题,最后我尝试使用其Uri更改DataTemplate)
public void UpdateResources(FrameworkElement elementToUpdate)
{
foreach(var controlDict in _registeredResources.Where(a => a.ControlType == elementToUpdate.GetType()))
{
//elementToUpdate.Resources.MergedDictionaries.Clear();
//elementToUpdate.Resources.MergedDictionaries.Add(controlDict);
//elementToUpdate.Resources = controlDict;
ResourceDictionary dict =new ResourceDictionary() { Source = new Uri("pack://application:,,,/ApplicationCore.UITest;component/NewDataTemplate.xaml") };
elementToUpdate.Resources = dict;
//elementToUpdate.Resources.MergedDictionaries.Clear();
//elementToUpdate.Resources.MergedDictionaries.Add(controlDict);
}
}
现在,当我按我的按钮更改DataTemplate时,ui不会使用新模板刷新。我不得不提到我并没有更改对象本身。
<ctrl:TreeViewControl DataContext="{Binding}">
<ctrl:TreeViewControl.Resources>
<ResourceDictionary Source="pack://application:,,,/OldDataTemplate.xaml"/>
</ctrl:TreeViewControl.Resources>
</ctrl:TreeViewControl>
我的问题:是否可以在运行时更改DataTemplate并刷新UI而无需更改绑定对象本身?
EDIT:我继续测试:ResourceDictionary(及其模板)已更改。一个新添加的项目(在更改模板后)将使用新的模板。但是旧项目不会更新。
1)如果您手动重新应用模板,即使使用StaticResources
也可以执行此操作:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:LParser">
<DataTemplate DataType="{x:Type local:MyContentClass1}">
<Border Background="Green" >
<TextBlock Text="{Binding MyContent}"/>
</Border>
</DataTemplate>
</ResourceDictionary>
<TreeView Name="my_trv" ItemsSource="{Binding MyItems.View}">
<TreeView.Resources>
<ResourceDictionary Source="pack://application:,,,/OldDataTemplate.xaml"/>
</TreeView.Resources>
</TreeView>
但是您必须在此处触摸TreeView:
FrameworkElement elementToUpdate = my_trv;
ResourceDictionary dict = new ResourceDictionary() { Source = new Uri("pack://application:,,,/NewDataTemplate.xaml") };
elementToUpdate.Resources = dict;
var dataTemplateKey = new DataTemplateKey(typeof(MyContentClass1));
var dataTemplate = (DataTemplate)dict[dataTemplateKey];
my_trv.ItemTemplate = dataTemplate;
2)如果您不想在特定资源中搜索资源,则可以使用DynamicResources
。如果您的商品中只能包含一种类型的数据,那么这相对容易,您只需命名模板即可:
<DataTemplate DataType="{x:Type local:MyContentClass1}" x:Key="MyTemplate1">
<Border Background="LightCoral" >
<TextBlock Text="{Binding MyContent}"/>
</Border>
</DataTemplate>
这样,您不必在后面的代码中显式地触摸控件:
<TreeView ItemsSource="{Binding MyItems.View}" ItemTemplate="{DynamicResource MyTemplate1}">
<TreeView.Resources>
<ResourceDictionary Source="pack://application:,,,/OldDataTemplate.xaml"/>
</TreeView.Resources>
</TreeView>
ResourceDictionary dict = new ResourceDictionary() { Source = new Uri("pack://application:,,,/NewDataTemplate.xaml") };
elementToUpdate.Resources = dict;
3)如果您具有多个具有不同模板的数据类型,则需要一些技巧。
首先,您为模板命名:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:LParser">
<DataTemplate DataType="{x:Type local:MyContentClass1}" x:Key="MyTemplate1">
<Border Background="Green">
<TextBlock Text="{Binding MyContent}"/>
</Border>
</DataTemplate>
<DataTemplate DataType="{x:Type local:MyContentClass2}" x:Key="MyTemplate2">
<Border Background="Blue">
<TextBlock Text="{Binding MyContent}"/>
</Border>
</DataTemplate>
</ResourceDictionary>
然后,在xaml中,您必须使用MergedDictionaries
代替,直接将ResourceDictionary
放置在Resources
节点中。
然后,有把戏。您将ContentPresenter
放入设置为DYnamicResources的DataTemplate
中,并使用正确的名称:
<TreeView ItemsSource="{Binding MyItems.View}">
<TreeView.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/OldDataTemplate.xaml"/>
</ResourceDictionary.MergedDictionaries>
<DataTemplate DataType="{x:Type local:MyContentClass1}" >
<ContentPresenter Content="{Binding}"
ContentTemplate="{DynamicResource MyTemplate1}" />
</DataTemplate>
<DataTemplate DataType="{x:Type local:MyContentClass2}" >
<ContentPresenter Content="{Binding}"
ContentTemplate="{DynamicResource MyTemplate2}" />
</DataTemplate>
</ResourceDictionary>
</TreeView.Resources>
</TreeView>
后面的代码将有所改变:
elementToUpdate.Resources.MergedDictionaries.Clear();
elementToUpdate.Resources.MergedDictionaries.Add(dict);