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

WPF如何扩展UserControl资源样式?遇资源字典初始化异常

问题:WPF自定义DataGrid UserControl样式扩展时的ResourceDictionary初始化异常

我基于DataGrid构建了一个带过滤功能的UserControl(过滤逻辑不赘述),控件功能复杂但运行正常(后续计划优化移除大量后台代码)。现在想扩展它的样式——让每个使用该UserControl的地方都能通过自定义转换器实现行分隔等显示效果,但遇到了以下异常:

System.Windows.Markup.XamlParseException: ''设置属性'System.Windows.ResourceDictionary.DeferrableContent'时引发异常。''
InvalidOperationException: 无法重新初始化ResourceDictionary实例。


自定义UserControl代码

<DataGrid x:Class="CustomDataGrid">

    <DataGrid.Resources>

        <!--  Data Grid Row Header  -->
        <Style x:Key="DataGridRowStyle" TargetType="{x:Type DataGridRow}">

            <!-- 我希望使用引用该UserControl的控件中定义的特定ControlTemplate(例如添加行分隔符) -->

        </Style>

    </DataGrid.Resources>

    <DataGrid.Style>

        <!--  DataGrid  -->
        <Style TargetType="{x:Type DataGrid}">

            <Setter Property="RowStyle" Value="{StaticResource DataGridRowStyle}" />

        </Style>

    </DataGrid.Style>

</DataGrid>

引用该控件的代码

<controls:CustomDataGrid>

    <controls:CustomDataGrid.Resources>

        <!--  Data Grid Row Header  -->
        <Style TargetType="{x:Type DataGridRow}">

            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type DataGridRow}">

                        <!-- ControlTemplate中包含Border、SelectiveScrollingGrid和DataGridCellsPresenter及特定值转换器等 -->

                    </ControlTemplate>
                </Setter.Value>
            </Setter>

        </Style>

    </controls:CustomDataGrid.Resources>

</controls:CustomDataGrid>

问题原因

自定义UserControl内部已定义DataGrid.Resources,引用控件时又试图重新设置CustomDataGrid.Resources,导致WPF尝试初始化已存在的ResourceDictionary实例,触发异常。

解决方法

方案1:通过依赖属性暴露行模板

在CustomDataGrid后台代码中定义依赖属性,允许传入自定义行模板:

public static readonly DependencyProperty RowTemplateProperty =
    DependencyProperty.Register("RowTemplate", typeof(ControlTemplate), typeof(CustomDataGrid),
        new PropertyMetadata(null, OnRowTemplateChanged));

public ControlTemplate RowTemplate
{
    get => (ControlTemplate)GetValue(RowTemplateProperty);
    set => SetValue(RowTemplateProperty, value);
}

private static void OnRowTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var dataGrid = d as CustomDataGrid;
    if (dataGrid?.RowStyle != null)
    {
        dataGrid.RowStyle.Setters.Add(new Setter(DataGridRow.TemplateProperty, e.NewValue));
    }
}

调整CustomDataGrid的XAML:

<DataGrid x:Class="CustomDataGrid">
    <DataGrid.RowStyle>
        <Style TargetType="{x:Type DataGridRow}">
            <!-- 保留默认样式设置,外部模板会覆盖对应属性 -->
        </Style>
    </DataGrid.RowStyle>
</DataGrid>

引用时直接设置属性:

<controls:CustomDataGrid>
    <controls:CustomDataGrid.RowTemplate>
        <ControlTemplate TargetType="{x:Type DataGridRow}">
            <!-- 自定义模板内容:Border、SelectiveScrollingGrid、DataGridCellsPresenter及转换器等 -->
        </ControlTemplate>
    </controls:CustomDataGrid.RowTemplate>
</controls:CustomDataGrid>

方案2:基于样式继承扩展

去掉自定义UserControl内部的DataGrid.Resources,让外部样式继承默认行样式:
修改CustomDataGrid的XAML:

<DataGrid x:Class="CustomDataGrid">
    <DataGrid.Style>
        <Style TargetType="{x:Type DataGrid}">
            <Setter Property="RowStyle">
                <Setter.Value>
                    <Style TargetType="{x:Type DataGridRow}">
                        <!-- 定义默认行样式 -->
                    </Style>
                </Setter.Value>
            </Setter>
        </Style>
    </DataGrid.Style>
</DataGrid>

引用时通过BasedOn继承并修改:

<controls:CustomDataGrid>
    <controls:CustomDataGrid.RowStyle>
        <Style TargetType="{x:Type DataGridRow}" BasedOn="{Binding RelativeSource={RelativeSource AncestorType=controls:CustomDataGrid}, Path=RowStyle}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type DataGridRow}">
                        <!-- 自定义模板内容 -->
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </controls:CustomDataGrid.RowStyle>
</controls:CustomDataGrid>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 05:17:15