2011-03-03 19 views
7

我尝试在Hyperlink上使用Style对象设置Foreground颜色,但其没有任何效果。我甚至使用Changing Hyperlink foreground without losing hover colorBasedOn提示,但它没有什么区别 - 我仍然会看到一个蓝色超链接,它在悬停时显示为红色。如何将样式传播到DataTemplate中的超链接?

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

<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> 

而且在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> 

这是值得注意的是,我不想直接在DataTemplateHyperlink上设置不同的颜色。这是因为模板将被使用不同的ItemsControl对象,其中大多数对象将在白色背景上,因此可以使用标准的超链接颜色。 (注意,上面的XAML中的那个背景是红色的。)

总之,我不希望DataTemplate必须知道任何有关使用它的控件。模板控件的样式应该过滤到它。

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

谢谢。

更新:
因为我不能让帕夫洛的答案在我的生产应用程序的工作,因为我已经尝试过在一个单独的测试程序。该应用程序是一个WinForms应用程序,主窗体仅包含一个ElementHost,它本身包含一个简单的WPF用户控件。下面是它的XAML:“只能与目标类型风格是基本类型‘IFrameworkInputElement’基地”

<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> 

正如上述表示,这将产生一个InvalidOperationException,说明

可以通过将TargetType="Hyperlink"置于UserControl.Resources元素内的Style定义上来修复这个问题。然而,当正在显示的信息,他们的链接部分仍然有默认的蓝色超链接样式:

Blue hyperlinks persist

总之,它不工作,所以我欢迎任何其他建议/更正。 :(

更新2:
感谢来自帕夫洛替代的解决方案,现在工作:)

回答

7

经过一番google搜索我碰到了这个帖子: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> 

然后,您可以添加一个隐含的样式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> 

而且因为数据模板可以在不同的地方使用,父容器可能没有使用键“MyDefaultHyperlinkStyle”定义样式。在这种情况下,将抛出一个异常,指出无法找到资源“MyDefaultHyperlinkStyle”。为了解决这个问题,你可以定义这样一个关键的风格,只会继承默认样式某处的App.xaml:

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

更新:

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

BasedOn="{StaticResource MyDefaultHyperlinkStyle}" 

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

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

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

您可能会倾向于使用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> 

它能正常工作,即内部StackPanel将所有链接黄色/白色,而在外面,他们将是蓝色的。

希望这会有所帮助。

+0

令人敬畏的谷歌搜索技巧 - 谢谢!还有一个非常完整的答案。我会试试这个,并将其标记为接受后,我有它的工作。 – 2011-03-03 17:47:30

+0

忘记我的应用程序是使用'ElementHost'的WinForms应用程序,所以我没有app.xaml文件。尽管如此,原理看起来很合理,所以我试着在我的UserControl资源字典中的DataTemplate之前添加一个空的MyDefaultHyperlinkStyle,并留下上面看到的特定的StackPanel以用它自己的定义替换它。可悲的是,它仍然无法正常工作。我会继续尝试...... – 2011-03-03 21:20:19

+0

@Mal - 你忘了在数据模板本身中包括样式:'