【问题标题】:How do I access an element of a parent template style in XAML?如何在 XAML 中访问父模板样式的元素?
【发布时间】:2018-01-22 09:42:09
【问题描述】:

在 WPF 中访问父模板样式的命名元素时遇到问题。

我有一个按钮的自定义控件(根据this StackOverflow question 编写):

CustomButton.xaml:

<ResourceDictionary ...>
<Style x:Key="ButtonCustomStyle" TargetType="{x:Type local:ImageButton}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:ImageButton}">
                <Grid>
                    <Image Source="{TemplateBinding Image}" Stretch="Fill" x:Name="CurrentImage"/>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter TargetName="CurrentImage" Property="Source" Value="{Binding ImageHover, RelativeSource={RelativeSource TemplatedParent}}"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

MainWindow.xaml:

<Window ...>
<Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="CustomButton.xaml"/>
        </ResourceDictionary.MergedDictionaries>
        <Style TargetType="{x:Type local:ImageButton}" BasedOn="{StaticResource ButtonCustomStyle}"/>
    </ResourceDictionary>
</Window.Resources>

<Grid>
    <local:ImageButton Image="\Images\image.png" ImageHover="\Images\image_hover.png" Width="20" Height="20"/>
</Grid>

ImageButton继承ButtonImageImageHover被定义为依赖属性。这段代码运行良好,符合预期。

现在,我想为单个特定按钮扩展此模板样式,添加一个额外的触发器来更改按钮的图像。我正在尝试执行以下操作:

<Window...>
<Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="CustomButton.xaml"/>
        </ResourceDictionary.MergedDictionaries>
        <Style TargetType="{x:Type local:ImageButton}" BasedOn="{StaticResource ButtonCustomStyle}"/>
        <Style TargetType="{x:Type local:ImageButton}"
               BasedOn="{StaticResource ButtonCustomStyle}"
               x:Key="Disableable">
            <Style.Triggers>
                <Trigger Property="IsEnabled" Value="False">
                    <Setter TargetName="CurrentImage" Property="Source" Value="\Images\disabled.png"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </ResourceDictionary>
</Window.Resources>

<Grid>
    <local:ImageButton Image="\Images\image.png" ImageHover="\Images\image_hover.png" Width="20" Height="20"/>
    <local:ImageButton Style="{StaticResource Disableable}" Image="\Images\image.png" ImageHover="\Images\image_hover.png" Width="20" Height="20"/>
</Grid>

但 Visual Studio 强调了新的 setter 行并表示 'The name "CurrentImage" is not recognized'

有没有办法改变CurrentImage 元素?

【问题讨论】:

    标签: c# wpf xaml


    【解决方案1】:

    在 WPF 中访问父模板样式的命名元素时遇到问题。

    这是不可能的。您不能将ControlTemplate 基于另一个ControlTemplate

    如果您希望 setter 能够找到在基 @ 的模板中定义的 CurrentImage 元素,恐怕您将不得不在派生的 Style 中从头开始重新定义整个 ControlTemplate 987654327@.

    WPF: Is there a way to override part of a ControlTemplate without redefining the whole style?

    但是,除了使用ControlTemplate 触发器,您应该能够使用设置控件本身的Image 属性的Style 触发器,而不是设置Image 元素的Source 属性模板:

    <Style x:Key="ButtonCustomStyle" TargetType="{x:Type local:ImageButton}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:ImageButton}">
                    <Grid>
                        <Image Source="{TemplateBinding Image}" Stretch="Fill" x:Name="CurrentImage"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="Image" Value="{Binding ImageHover, RelativeSource={RelativeSource Self}}"/>
            </Trigger>
        </Style.Triggers>
    </Style>
    
    <Style TargetType="{x:Type local:ImageButton}"
                   BasedOn="{StaticResource ButtonCustomStyle}"
                   x:Key="Disableable">
        <Style.Triggers>
            <Trigger Property="IsEnabled" Value="False">
                <Setter Property="Image" Value="\Images\disabled.png"/>
            </Trigger>
        </Style.Triggers>
    </Style>
    

    【讨论】:

    • 这有点离题,但是当我注释掉 &lt;ControlTemplate.Triggers&gt; 部分并插入 &lt;Style.Triggers&gt; 部分时,悬停时的图像更改停止工作。当我注释掉&lt;Style.Triggers&gt; 并取消注释&lt;ControlTemplate.Triggers&gt; 时,它又开始工作了。可能是 Image 属性定义的东西吗?它是在我的问题中提到的那个 SO 问题之后写的。
    • 尝试按照我编辑的答案使用RelativeSource Self。
    • 无济于事:(我复制了您的样式定义;从Window.Resources 中删除了所有额外内容。带有&lt;Style.Triggers&gt; 的代码不响应鼠标悬停;带有&lt;ControlTemplate.Triggers&gt; 的代码可以。
    • 怎么样?
    • 不,这也没有帮助。好吧,我想,很难远程进行调试。这可能与我的代码有关,尽管 ControlTemplate 触发器有效而 Style 触发器无效,这很奇怪。
    【解决方案2】:

    与 ControlTemplete 触发器不同,Style 触发器无法访问模板元素。由于您暴露了Image 属性,请在样式触发器设置器中使用它:

    <Trigger Property="IsEnabled" Value="False">
        <Setter Property="Image" Value="\Images\disabled.png"/>
    </Trigger>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-07
      • 2023-03-27
      相关资源
      最近更新 更多