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

如何在自定义控件中通过ComponentResourceKey修改内部自定义控件样式

解决MyCustomControl内部修改MyToggleButton的ButtonBrush问题

你遇到的核心问题是:用ComponentResourceKey定义的ButtonBrushKey,资源查找逻辑会优先从应用程序级、主题级资源字典中查找。你之前在MyCustomControl的Style根节点定义资源,这个层级不在MyToggleButton的资源查找路径内,所以不生效;而Window的Resources是全局层级,能被所有子元素找到,因此可以生效。

下面提供三种可行的解决办法:


方法一:在ControlTemplate内部定义资源

将修改ButtonBrush的资源放在MyCustomControl的ControlTemplate的Resources中,作为子元素的MyToggleButton就能正确识别到该资源:

<Style TargetType="{x:Type ctrl:MyCustomControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ctrl:MyCustomControl}">
                <!-- 把资源放在ControlTemplate的Resources中 -->
                <ControlTemplate.Resources>
                    <SolidColorBrush x:Key="{x:Static toggle:MyToggleButton.ButtonBrushKey}" Color="Green" />
                </ControlTemplate.Resources>
                
                <Border BorderBrush="SteelBlue"
                        BorderThickness="2"
                        Background="LightGray">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition Width="Auto"/>
                        </Grid.ColumnDefinitions>

                        <toggle:MyToggleButton Grid.Column="0"
                                                VerticalAlignment="Center"
                                                Height="45"
                                                Width="100"
                                                Margin="5,0,0,0"/>

                        <TextBlock Grid.Column="1" 
                                    VerticalAlignment="Center"
                                    Text="Some Text"
                                    FontWeight="Bold"
                                    Margin="5,0,0,0"/>
                    </Grid>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

这种方式会让MyCustomControl内部所有的MyToggleButton都使用该颜色的ButtonBrush。


方法二:单独给MyToggleButton实例设置资源

如果只想修改当前这个特定的MyToggleButton实例,直接在它自身的Resources节点中定义即可:

<toggle:MyToggleButton Grid.Column="0"
                        VerticalAlignment="Center"
                        Height="45"
                        Width="100"
                        Margin="5,0,0,0">
    <toggle:MyToggleButton.Resources>
        <SolidColorBrush x:Key="{x:Static toggle:MyToggleButton.ButtonBrushKey}" Color="Green" />
    </toggle:MyToggleButton.Resources>
</toggle:MyToggleButton>

方法三:改用依赖属性(推荐)

使用ComponentResourceKey的方式灵活性不足,将ButtonBrush改为MyToggleButton的依赖属性是WPF自定义控件的最佳实践,这样可以像普通控件属性一样直接设置,还支持绑定、样式Setter等操作。

1. 修改MyToggleButton后台代码

public class MyToggleButton : ToggleButton
{
    // 定义ButtonBrush依赖属性
    public static readonly DependencyProperty ButtonBrushProperty =
        DependencyProperty.Register(
            nameof(ButtonBrush), 
            typeof(Brush), 
            typeof(MyToggleButton), 
            new PropertyMetadata(Brushes.Red)); // 默认红色

    public Brush ButtonBrush
    {
        get => (Brush)GetValue(ButtonBrushProperty);
        set => SetValue(ButtonBrushProperty, value);
    }

    static MyToggleButton()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MyToggleButton), 
            new FrameworkPropertyMetadata(typeof(MyToggleButton)));
    }
}

2. 更新Generic.xaml中的模板

把原来的DynamicResource绑定替换为TemplateBinding,关联到新的依赖属性:

<Style TargetType="{x:Type ctrl:MyToggleButton}">
    <Setter Property="Background" Value="SteelBlue"/>
    <Setter Property="BorderBrush" Value="Green"/>
    <Setter Property="BorderThickness" Value="2"/>
    <Setter Property="Height" Value="28"/>
    <Setter Property="Width" Value="65"/>
    <Setter Property="ButtonBrush" Value="Red"/> <!-- 设置默认值 -->

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ctrl:MyToggleButton}">
                <Border x:Name="back" 
                    BorderBrush="{Binding BorderBrush, RelativeSource={RelativeSource TemplatedParent}}"
                    Background="{Binding Background, RelativeSource={RelativeSource TemplatedParent}}"
                    BorderThickness="{Binding BorderThickness, RelativeSource={RelativeSource TemplatedParent}}"
                    CornerRadius="5">

                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>

                        <!-- 修改Background为TemplateBinding ButtonBrush -->
                        <Border x:Name="button" 
                            Grid.Column="0" 
                            Grid.ColumnSpan="2"
                            Background="{TemplateBinding ButtonBrush}"
                            Width="16" 
                            Height="16" 
                            Margin="2"
                            CornerRadius="3"
                            HorizontalAlignment="Left">

                            <!-- 修改Fill为TemplateBinding ButtonBrush -->
                            <Path x:Name="icon" 
                                    Fill="{TemplateBinding ButtonBrush}"
                                    Stretch="Uniform"
                                    HorizontalAlignment="Center"
                                    VerticalAlignment="Center"
                                    Margin="2"
                                    Data="{Binding OnPathData, RelativeSource={RelativeSource TemplatedParent}}"/>

                        </Border>

                        <TextBlock x:Name="text" 
                                    Grid.Column="1"
                                    Text="On"
                                    FontSize="12"
                                    Foreground="White"
                                    HorizontalAlignment="Center"
                                    VerticalAlignment="Center"/>

                    </Grid>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

3. 在MyCustomControl中直接设置属性

现在可以像设置Width、Height一样,直接给MyToggleButton设置ButtonBrush属性:

<toggle:MyToggleButton Grid.Column="0"
                        VerticalAlignment="Center"
                        Height="45"
                        Width="100"
                        Margin="5,0,0,0"
                        ButtonBrush="Green"/>

这种方式还支持样式Setter、数据绑定等高级操作,比如可以在MyCustomControl的Style中统一设置内部所有MyToggleButton的ButtonBrush。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 17:25:56