如何将样式传播到DataTemplate中的超链接?

Mal*_*oss 7 wpf xaml styles datatemplate hyperlink

我尝试使用祖先的对象设置Foreground颜色,但它没有任何效果.我甚至使用了更改超链接前景的提示而没有丢失悬停颜色,但它没有任何区别 - 我仍然得到一个悬停时为红色的蓝色超链接.HyperlinkStyleResourcesBasedOn

这是我的控件的XAML,包括ItemsControl使用超链接显示其项目的XAML :

<StackPanel Background="Red" TextElement.Foreground="White">
  <StackPanel.Resources>
    <Style TargetType="Hyperlink" BasedOn="{StaticResource {x:Type Hyperlink}}">
      <Setter Property="Foreground" Value="Yellow"/>
      <Style.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
          <Setter Property="Foreground" Value="White"/>
        </Trigger>
      </Style.Triggers>
    </Style>
  </StackPanel.Resources>
  <TextBlock>Data import errors</TextBlock>
  <ItemsControl ItemsSource="{Binding Errors}"/>
</StackPanel>
Run Code Online (Sandbox Code Playgroud)

而且这些项目ItemsControl正在取得以下成果DataTemplate:

<DataTemplate DataType="{x:Type Importer:ConversionDetailsMessage}">
  <TextBlock>
    <Run Text="{Binding Message, Mode=OneTime}"/>
    <Hyperlink Command="Common:ImportDataCommands.ExplainConversionMessage" CommandParameter="{Binding}">
      <Run Text="{Binding HelpLink.Item2, Mode=OneTime}"/>
    </Hyperlink>
  </TextBlock>
</DataTemplate>
Run Code Online (Sandbox Code Playgroud)

值得一提的,那就是,我不想只是上直接设置不同颜色HyperlinkDataTemplate.这是因为模板将被许多不同的ItemsControl对象使用,其中大部分将在白色背景上,因此可以使用标准的超链接颜色.(请注意,上面XAML中的那个具有红色背景.)

简而言之,我不希望DataTemplate它对使用它的控件有任何了解.模板控件的样式应该只过滤到它.

所以...有谁能告诉我为什么风格没有过滤掉我可以做些什么来解决它?

谢谢.

更新:
由于我无法让Pavlo的答案在我的生产应用程序中工作,我已经在一个单独的测试应用程序中尝试过.该应用程序是一个WinForms应用程序,主要表单只包含一个ElementHost,它本身包含一个简单的WPF用户控件.这是它的XAML:

<UserControl x:Class="DataTemplateStyling.StylingView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:DataTemplateStyling="clr-namespace:DataTemplateStyling"
             x:Name="root" Loaded="StylingViewLoaded">

  <UserControl.Resources>
    <Style x:Key="MyDefaultHyperlinkStyle" BasedOn="{StaticResource {x:Type Hyperlink}}"/>

    <DataTemplate DataType="{x:Type DataTemplateStyling:ImportMessage}">
      <DataTemplate.Resources>
        <Style TargetType="{x:Type Hyperlink}"
               BasedOn="{StaticResource MyDefaultHyperlinkStyle}"/>
      </DataTemplate.Resources>
      <TextBlock>
        <Run Text="{Binding Message, Mode=OneTime}"/>
        <Hyperlink NavigateUri="{Binding HelpLink.Item1}">
          <Run Text="{Binding HelpLink.Item2, Mode=OneTime}"/>
        </Hyperlink>
      </TextBlock>
    </DataTemplate>
  </UserControl.Resources>

  <Grid DataContext="{Binding ElementName=root}">
    <StackPanel Background="Red" TextElement.Foreground="White">
      <StackPanel.Resources>
        <Style x:Key="MyDefaultHyperlinkStyle" TargetType="Hyperlink" BasedOn="{StaticResource {x:Type Hyperlink}}">
          <Setter Property="Foreground" Value="Yellow"/>
          <Style.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
              <Setter Property="Foreground" Value="White"/>
            </Trigger>
          </Style.Triggers>
        </Style>
      </StackPanel.Resources>
      <TextBlock>Data import errors</TextBlock>
      <ItemsControl ItemsSource="{Binding Messages}"/>
    </StackPanel>
  </Grid>
</UserControl>
Run Code Online (Sandbox Code Playgroud)

如上所示,这会产生一个InvalidOperationException声明"只能基于具有基本类型'IFrameworkInputElement'的目标类型的样式."

这可以通过将固定TargetType="Hyperlink"Style里面立即定义UserControl.Resources元素.但是,在显示消息时,它们的链接部分仍然具有默认的蓝色超链接样式:

蓝色超链接仍然存在

简而言之,它不起作用,所以我欢迎任何其他建议/更正.:(

更新2:
得益于Pavlo的替代解决方案,它现在正在运行.:)

Pav*_*kov 7

经过一些谷歌搜索后,我遇到了这篇文章:http://www.11011.net/archives/000692.html.

正如它在那里描述的那样,事实证明,不是从Control(和TextBlockHyperlink)派生的元素不会在DataTemplate边界之外寻找隐式样式.

同样,正如文章所说,可能的解决方法是明确指定样式键.在你的情况下,它可能是这样的:

<StackPanel Background="Red" TextElement.Foreground="White">
  <StackPanel.Resources>
    <Style x:Key="MyDefaultHyperlinkStyle" TargetType="Hyperlink" BasedOn="{StaticResource {x:Type Hyperlink}}">
      <Setter Property="Foreground" Value="Yellow"/>
      <Style.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
          <Setter Property="Foreground" Value="White"/>
        </Trigger>
      </Style.Triggers>
    </Style>
  </StackPanel.Resources>
  <TextBlock>Data import errors</TextBlock>
  <ItemsControl ItemsSource="{Binding Errors}"/>
</StackPanel>
Run Code Online (Sandbox Code Playgroud)

然后,您可以添加一个隐式样式Hyperlink,只是在DataTemplate资源中引用我们的命名样式:

<DataTemplate DataType="{x:Type Importer:ConversionDetailsMessage}">
  <DataTemplate.Resources>
    <Style TargetType="{x:Type Hyperlink}"
           BasedOn="{StaticResource MyDefaultHyperlinkStyle}"/>
  </DataTemplate.Resources>
  <TextBlock>
    <Run Text="{Binding Message, Mode=OneTime}"/>
    <Hyperlink Command="Common:ImportDataCommands.ExplainConversionMessage" CommandParameter="{Binding}">
      <Run Text="{Binding HelpLink.Item2, Mode=OneTime}"/>
    </Hyperlink>
  </TextBlock>
</DataTemplate>
Run Code Online (Sandbox Code Playgroud)

并且因为数据模板可以在不同的地方使用,所以父容器可能没有定义具有键"MyDefaultHyperlinkStyle"的样式.在这种情况下,将抛出异常,说无法找到资源"MyDefaultHyperlinkStyle".要解决此问题,您可以使用此类键定义样式,该样式仅在App.xaml中的某处继承默认样式:

<Style x:Key="MyDefaultHyperlinkStyle"
       BasedOn="{StaticResource {x:Type Hyperlink}}/>
Run Code Online (Sandbox Code Playgroud)

更新:

由于静态资源的性质,您在更新中包含的代码将无法工作,这意味着日期模板中的以下资源引用...

BasedOn="{StaticResource MyDefaultHyperlinkStyle}"
Run Code Online (Sandbox Code Playgroud)

...将始终指向以下资源(这是默认样式):

<Style x:Key="MyDefaultHyperlinkStyle" BasedOn="{StaticResource {x:Type Hyperlink}}"/>
Run Code Online (Sandbox Code Playgroud)

静态资源引用在编译时解析,因此使用树中最近的资源.

您可能很想使用DynamicResource,但不幸的是,该BasedOn属性不支持.

但是,Foreground属性支持动态资源,因此我们可以在我们的样式中使用相同的技巧.以下是修改为使用动态画笔的测试用户控件:

<UserControl x:Class="DataTemplateStyling.StylingView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:DataTemplateStyling="clr-namespace:DataTemplateStyling"
             x:Name="root"
             Loaded="StylingViewLoaded">

    <UserControl.Resources>
        <SolidColorBrush x:Key="HyperlinkForeground"
                         Color="Blue" />

        <SolidColorBrush x:Key="HyperlinkHoverForeground"
                         Color="Gray" />

        <Style x:Key="MyDefaultHyperlinkStyle"
               TargetType="Hyperlink"
               BasedOn="{StaticResource {x:Type Hyperlink}}">
            <Setter Property="Foreground"
                    Value="{DynamicResource HyperlinkForeground}" />
            <Style.Triggers>
                <Trigger Property="IsMouseOver"
                         Value="True">
                    <Setter Property="Foreground"
                            Value="{DynamicResource HyperlinkHoverForeground}" />
                </Trigger>
            </Style.Triggers>
        </Style>

        <DataTemplate DataType="{x:Type DataTemplateStyling:ImportMessage}">
            <DataTemplate.Resources>
                <Style TargetType="{x:Type Hyperlink}"
                       BasedOn="{StaticResource MyDefaultHyperlinkStyle}" />
            </DataTemplate.Resources>
            <TextBlock>
                <Run Text="{Binding Message, Mode=OneTime}" />
                <Hyperlink NavigateUri="{Binding HelpLink.Item1}">
                    <Run Text="{Binding HelpLink.Item2, Mode=OneTime}" />
                </Hyperlink>
            </TextBlock>
        </DataTemplate>
    </UserControl.Resources>

    <Grid DataContext="{Binding ElementName=root}">
        <StackPanel Background="Red"
                    TextElement.Foreground="White">
            <StackPanel.Resources>
                <SolidColorBrush x:Key="HyperlinkForeground"
                                 Color="Yellow" />

                <SolidColorBrush x:Key="HyperlinkHoverForeground"
                                 Color="White" />
            </StackPanel.Resources>
            <TextBlock>Data import errors</TextBlock>
            <ItemsControl ItemsSource="{Binding Messages}" />
        </StackPanel>
    </Grid>
</UserControl>
Run Code Online (Sandbox Code Playgroud)

它按预期工作,即内部的所有链接StackPanel都是黄色/白色,而外面的链接是蓝色.

希望这可以帮助.