在运行时更改DataTemplate

时间:2019-11-15 07:22:32

标签: c# wpf datatemplate

我将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,而无需更改绑定对象本身?

编辑:我继续测试:ResourceDictionary(及其模板)已更改。一个新添加的项目(在更改模板后)将使用新的模板。但是旧项目不会更新。 enter image description here

1 个答案:

答案 0 :(得分:1)

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:MyProject">
<DataTemplate DataType="{x:Type local:MyContentClass1}">
    <Border Background="Green" >
        <TextBlock Text="{Binding MyContent}"/>
    </Border>
</DataTemplate>
</ResourceDictionary>

<TreeView Name="my_trv" DataContext="{Binding}">
     <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 DataContext="{Binding}" 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:MyProject">

<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放入DataTemplate内,并设置为DynamicResources,并使用正确的名称:

<TreeView DataContext="{Binding}">
    <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);