DependencyProperty 在 ResourceDictionary 中找不到项目

发布于 2024-12-20 10:47:17 字数 3741 浏览 5 评论 0原文

目前我正在尝试模仿 FlowDocument 环境中 ContentControl 控件的行为。我喜欢 ContentControl,因为它允许根据内容的类型在不同的模板中显示内容。例如:

<ContentControl Content={Binding}/>

将使用在 ResourceDictionary 的 XAML 中定义的 DataTemplates:

<DataTemplate DataType={x:Type local:Person}>...</DataType>
<DataTemplate DataType={x:Type local:Pet}>...</DataType>

现在为了复制此行为以用于我的 FlowDocument 替代方案,我开始搜索互联网。我遇到了使用流文档和数据绑定创建灵活的 UI帮了很多忙。首先,我按如下方式更改了 ItemsContent:

public class TemplatedContent : Section
{
    private static readonly DependencyProperty ContentProperty = DependencyProperty.Register("Content", typeof(object), typeof(TemplatedContent), new PropertyMetadata(OnContentChanged));
    private static readonly DependencyProperty TemplateProperty = DependencyProperty.Register("Template", typeof(DataTemplate), typeof(TemplatedContent), new PropertyMetadata(OnTemplateChanged));

    public TemplatedContent()
    {
        //Helpers.FixupDataContext(this);
        Loaded += TemplatedContent_Loaded;
    }

    private void TemplatedContent_Loaded(object sender, RoutedEventArgs e)
    {
        GenerateContent(Template, Content);
    }

    public object Content
    {
        get { return GetValue(ContentProperty); }
        set { SetValue(ContentProperty, value); }
    }

    public DataTemplate Template
    {
        get { return (DataTemplate)GetValue(TemplateProperty); }
        set { SetValue(TemplateProperty, value); }
    }


    private void GenerateContent(DataTemplate template, object content)
    {
        Blocks.Clear();
        if (template != null && content != null)
        {
            FrameworkContentElement element = Helpers.LoadDataTemplate(template);
            element.DataContext = content;
            //Helpers.UnFixupDataContext(element);
            Blocks.Add(Helpers.ConvertToBlock(content, element));
        }
    }

    private void GenerateContent()
    {
        GenerateContent(Template, Content);
    }

    private void OnContentChanged(object newValue)
    {
        if (IsLoaded)
            GenerateContent(Template, newValue);
    }

    private void OnTemplateChanged(DataTemplate newValue)
    {
        if (IsLoaded)
            GenerateContent(newValue, Content);
    }

    private static void OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((TemplatedContent)d).OnContentChanged(e.NewValue);
    }

    private static void OnTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((TemplatedContent)d).OnTemplateChanged((DataTemplate)e.NewValue);
    }
}

如您所见,这是非常基本的代码和平,当我以以下方式使用它时,它会按预期工作:

 <FlowDocument>
     <local:TemplatedContent Content={Binding}>
        <local:TemplatedContent.Template>
           <DataTemplate DataType={x:Type local:Person}>...</DataTemplate>
        </local:TemplatedContent.Template>
     </local:TemplatedContent>
 </FlowDocument>

这一切都很好,但为了支持不同内容类型的多个模板,我将需要在资源字典中定义DataTemplates:

<FlowDocument>
    <local:TemplatedContent Content={Binding}>
    </local:TemplatedContent>
</FlowDocument>

并且在资源字典中更高:

 <DataTemplate DataType={x:Type local:Person}>...</DataTemplate>

现在,TemplatedContent无法找到DataTemplate。这怎么可能?如果我正确理解了 DependencyProperty 的理论,它应该在 xaml 树中查找与内容类型匹配的条目,对吧?事实并非如此。当在线设置断点时:

private static void OnTemplateChanged

它永远不会被调用。

希望各位专家能进一步帮助我解决这个问题!

提前非常感谢!

Currently i'm trying to mimic the behavior of the ContentControl Control in a FlowDocument environment. I like the ContentControl because it allows to display content in a different template based on the content's type. E.g.:

<ContentControl Content={Binding}/>

will use DataTemplates defined higer up in the XAML in a ResourceDictionary:

<DataTemplate DataType={x:Type local:Person}>...</DataType>
<DataTemplate DataType={x:Type local:Pet}>...</DataType>

Now to copy this behavior for my FlowDocument alternative i started searching the internet. I the came across Create Flexible UIs With Flow Documents And Data Binding which really helped a lot. As a start I altered the ItemsContent as follows:

public class TemplatedContent : Section
{
    private static readonly DependencyProperty ContentProperty = DependencyProperty.Register("Content", typeof(object), typeof(TemplatedContent), new PropertyMetadata(OnContentChanged));
    private static readonly DependencyProperty TemplateProperty = DependencyProperty.Register("Template", typeof(DataTemplate), typeof(TemplatedContent), new PropertyMetadata(OnTemplateChanged));

    public TemplatedContent()
    {
        //Helpers.FixupDataContext(this);
        Loaded += TemplatedContent_Loaded;
    }

    private void TemplatedContent_Loaded(object sender, RoutedEventArgs e)
    {
        GenerateContent(Template, Content);
    }

    public object Content
    {
        get { return GetValue(ContentProperty); }
        set { SetValue(ContentProperty, value); }
    }

    public DataTemplate Template
    {
        get { return (DataTemplate)GetValue(TemplateProperty); }
        set { SetValue(TemplateProperty, value); }
    }


    private void GenerateContent(DataTemplate template, object content)
    {
        Blocks.Clear();
        if (template != null && content != null)
        {
            FrameworkContentElement element = Helpers.LoadDataTemplate(template);
            element.DataContext = content;
            //Helpers.UnFixupDataContext(element);
            Blocks.Add(Helpers.ConvertToBlock(content, element));
        }
    }

    private void GenerateContent()
    {
        GenerateContent(Template, Content);
    }

    private void OnContentChanged(object newValue)
    {
        if (IsLoaded)
            GenerateContent(Template, newValue);
    }

    private void OnTemplateChanged(DataTemplate newValue)
    {
        if (IsLoaded)
            GenerateContent(newValue, Content);
    }

    private static void OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((TemplatedContent)d).OnContentChanged(e.NewValue);
    }

    private static void OnTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((TemplatedContent)d).OnTemplateChanged((DataTemplate)e.NewValue);
    }
}

As you can see it's a verly basic peace of code and it works as expected when i use it in the following manner:

 <FlowDocument>
     <local:TemplatedContent Content={Binding}>
        <local:TemplatedContent.Template>
           <DataTemplate DataType={x:Type local:Person}>...</DataTemplate>
        </local:TemplatedContent.Template>
     </local:TemplatedContent>
 </FlowDocument>

This is all well but to support multiple templates for different content types i will need to define the DataTemplates in a resource dictionary:

<FlowDocument>
    <local:TemplatedContent Content={Binding}>
    </local:TemplatedContent>
</FlowDocument>

and higer up in a resource dictionary:

 <DataTemplate DataType={x:Type local:Person}>...</DataTemplate>

Now, the TemplatedContent is unable to find the DataTemplate. How is this possible? If I understand the theory around DependencyProperty correctly it should look in the xaml tree for entries that match the type of the content right? It doesn't. When setting a breakpoint on line:

private static void OnTemplateChanged

it's never called.

I hope you experts can help me further with this!

Lots of thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

凉风有信 2024-12-27 10:47:17

您需要在资源字典中定义模板,如下所示:

<FlowDocument>
    <FlowDocument.Resources>
        <DataTemplate x:Key="MyDataTemplate">
            <!-- Contents of template go here -->
        </DataTemplate>
    </FlowDocument.Resources>
    <!-- document content here -->
</FlowDocument>

现在对模板的引用是通过 StaticResource 标记扩展完成的:

<local:TemplateContent Content="{Binding}" Template="{StaticResource MyDataTemplate}" />

希望这会有所帮助!

You need to define the template in your resource dictionary like so:

<FlowDocument>
    <FlowDocument.Resources>
        <DataTemplate x:Key="MyDataTemplate">
            <!-- Contents of template go here -->
        </DataTemplate>
    </FlowDocument.Resources>
    <!-- document content here -->
</FlowDocument>

And the reference to your template is now done with a StaticResource markup extension:

<local:TemplateContent Content="{Binding}" Template="{StaticResource MyDataTemplate}" />

Hope this helps!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文