You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为WPF自定义控件内的ContentPresenter指定专属ResourceDictionary

解决方案

你遇到的报错原因是ResourceDictionary本身没有继承DependencyObject,它的Source属性是普通CLR属性,不支持绑定赋值,所以你之前的写法无法生效。有两种成熟的实现方案可以满足你的需求:

方案1:通过依赖属性回调手动注入资源(适合ContentPresenter可直接访问的场景)

  1. 在自定义控件的后台代码中定义两个ResourceDictionary类型的依赖属性,并指定属性变更回调:
public static readonly DependencyProperty HeaderResourcesProperty = DependencyProperty.Register(
    nameof(HeaderResources), typeof(ResourceDictionary), typeof(DynamicDataGridControl), 
    new PropertyMetadata(null, OnHeaderResourcesChanged));

public ResourceDictionary HeaderResources
{
    get => (ResourceDictionary)GetValue(HeaderResourcesProperty);
    set => SetValue(HeaderResourcesProperty, value);
}

public static readonly DependencyProperty CellResourcesProperty = DependencyProperty.Register(
    nameof(CellResources), typeof(ResourceDictionary), typeof(DynamicDataGridControl), 
    new PropertyMetadata(null, OnCellResourcesChanged));

public ResourceDictionary CellResources
{
    get => (ResourceDictionary)GetValue(CellResourcesProperty);
    set => SetValue(CellResourcesProperty, value);
}

private static void OnHeaderResourcesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var control = (DynamicDataGridControl)d;
    if (e.NewValue is ResourceDictionary res)
    {
        control.HeaderPresenter.Resources.MergedDictionaries.Clear();
        control.HeaderPresenter.Resources.MergedDictionaries.Add(res);
    }
}

private static void OnCellResourcesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var control = (DynamicDataGridControl)d;
    if (e.NewValue is ResourceDictionary res)
    {
        control.CellPresenter.Resources.MergedDictionaries.Clear();
        control.CellPresenter.Resources.MergedDictionaries.Add(res);
    }
}
  1. 使用者调用时直接传入资源字典即可:
<UserControl.Resources>
    <ResourceDictionary x:Key="HeaderRes">
        <DataTemplate DataType="{x:Type local:MyData}">
            <!-- 头部模板 -->
        </DataTemplate>
    </ResourceDictionary>
    <ResourceDictionary x:Key="CellRes">
        <DataTemplate DataType="{x:Type local:MyData}">
            <!-- 单元格模板 -->
        </DataTemplate>
    </ResourceDictionary>
</UserControl.Resources>

<CustomControl HeaderResources="{StaticResource HeaderRes}" CellResources="{StaticResource CellRes}"/>

方案2:使用附加属性实现(适合ContentPresenter在DataTemplate内部、无法直接按名称访问的场景)

针对你提到的两个ContentPresenter属于DataTemplate一部分的情况,用附加属性可以更灵活地完成资源注入:

  1. 定义附加属性类:
public static class ContentPresenterResources
{
    public static readonly DependencyProperty CustomResourcesProperty = DependencyProperty.RegisterAttached(
        "CustomResources", typeof(ResourceDictionary), typeof(ContentPresenterResources), 
        new PropertyMetadata(null, OnCustomResourcesChanged));

    public static void SetCustomResources(DependencyObject element, ResourceDictionary value)
    {
        element.SetValue(CustomResourcesProperty, value);
    }

    public static ResourceDictionary GetCustomResources(DependencyObject element)
    {
        return (ResourceDictionary)element.GetValue(CustomResourcesProperty);
    }

    private static void OnCustomResourcesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is not ContentPresenter presenter || e.NewValue is not ResourceDictionary res) 
            return;
        presenter.Resources.MergedDictionaries.Clear();
        presenter.Resources.MergedDictionaries.Add(res);
    }
}
  1. 在自定义控件的XAML中绑定附加属性:
<ContentPresenter x:Name="HeaderPresenter" 
    local:ContentPresenterResources.CustomResources="{Binding ElementName=self, Path=HeaderResources}"/>
<ContentPresenter x:Name="CellPresenter" 
    local:ContentPresenterResources.CustomResources="{Binding ElementName=self, Path=CellResources}"/>

使用方式和方案1完全一致,不需要修改使用者的调用代码。

两种方案都可以实现相同数据类型在两个ContentPresenter中匹配不同的隐式DataTemplate的需求,不需要额外转换器,性能也没有明显损失。


内容的提问来源于stack exchange,提问作者mike

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 03:15:03