简体   繁体   English

在运行时更改 DataTemplate

[英]Changing DataTemplate during Runtime

I use a ResourceProvider as global management for my ResourceDictionaries.我使用ResourceProvider作为我的 ResourceDictionaries 的全局管理。 I register new ResourceDictionaries to the ResourceProvider and raise a event for each affected FrameworkElement.我将新的 ResourceDictionaries 注册到 ResourceProvider 并为每个受影响的 FrameworkElement 引发一个事件。 The FrameworkElement then updates its resources with the following method: (I tried several ways to fix this and at the End i tried to change the DataTemplate with its Uri)然后,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);
        }
    }

Right now when i press my Button to Change the DataTemplate the ui doesn't refresh with the new template.现在,当我按下按钮更改 DataTemplate 时,用户界面不会使用新模板刷新。 I have to mention that I'm not changing the object itself.我不得不提一下,我并没有改变 object 本身。

                 <ctrl:TreeViewControl DataContext="{Binding}">
                    <ctrl:TreeViewControl.Resources>
                        <ResourceDictionary Source="pack://application:,,,/OldDataTemplate.xaml"/>
                    </ctrl:TreeViewControl.Resources>
                </ctrl:TreeViewControl>

My Question: Is it possible to change a DataTemplate during Runtime and refresh the UI without changing the bound object itself?我的问题:是否可以在运行时更改 DataTemplate 并刷新 UI 而无需更改绑定的 object 本身?

EDIT: I continued testing: The ResourceDictionary (with its Template) is changed.编辑:我继续测试:ResourceDictionary(及其模板)已更改。 A new added item (after the Template change) uses the new Template.新添加的项目(模板更改后)使用新模板。 But the old items are not updated.但是旧项目没有更新。 在此处输入图像描述

1) You could do it even with StaticResources if you reapply the template manually: 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>

But you'll have to touch the TreeView here:但是您必须在此处触摸 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) If you do not want to search your resources for a specific one, you could use DynamicResources . 2)如果您不想在资源中搜索特定资源,可以使用DynamicResources If there could only be one type of data in your Items, then it is relatively easy, you only have to name your template:如果您的 Items 中只能有一种类型的数据,那么这相对容易,您只需为您的模板命名:

<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>

This way you do not have to touch your control explicitly in the codebehind:这样您就不必在代码隐藏中显式地触摸您的控件:

ResourceDictionary dict = new ResourceDictionary() { Source = new Uri("pack://application:,,,/NewDataTemplate.xaml") };
elementToUpdate.Resources = dict;

3) If you have more than one type of data with different templates, then a bit of a trick is necessary. 3) 如果你有不止一种类型的不同模板的数据,那么需要一些技巧。

First, you name your templates:首先,你命名你的模板:

<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>

Then, in xaml, you'll have to use MergedDictionaries instead of putting your ResourceDictionary directly in the Resources node.然后,在 xaml 中,您必须使用MergedDictionaries而不是将ResourceDictionary直接放在Resources节点中。

Then, there is the trick.然后,有诀窍。 You put ContentPresenter inside DataTemplate set to DynamicResources with the correct name:您将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>

The code-behind will change a bit:代码隐藏会有所改变:

elementToUpdate.Resources.MergedDictionaries.Clear();
elementToUpdate.Resources.MergedDictionaries.Add(dict);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM