如何将样式传播到DataTemplate中的超链接? [英] How to propagate styles to Hyperlinks inside a DataTemplate?

查看:167
本文介绍了如何将样式传播到DataTemplate中的超链接?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试使用样式在超链接上设置前景颜色祖先的资源中的对象,但它没有任何效果。我甚至使用。



正如它在那里描述的那样,结果是那些不是从 Control 派生的元素(如 TextBlock 超链接)不要在 DataTemplate 边界之外查找隐式样式。



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

 < StackPanel Background =RedTextElement.Foreground =White> ; 
< StackPanel.Resources>
< Style x:Key =MyDefaultHyperlinkStyleTargetType =HyperlinkBasedOn ={StaticResource {x:Type Hyperlink}}>
< Setter Property =ForegroundValue =Yellow/>
< Style.Triggers>
< Trigger Property =IsMouseOverValue =True>
< Setter Property =ForegroundValue =White/>
< / Trigger>
< /Style.Triggers>
< / Style>
< /StackPanel.Resources>
< TextBlock>数据导入错误< / TextBlock>
< ItemsControl ItemsSource ={Binding Errors}/>
< / StackPanel>

然后,您可以为超链接只是在 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.ExplainConversionMessageCommandParameter ={Binding}>
< Run Text ={Binding HelpLink.Item2,Mode = OneTime}/>
< / Hyperlink>
< / TextBlock>
< / DataTemplate>

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

 <样式x:Key =MyDefaultHyperlinkStyle
BasedOn ={StaticResource {x:Type Hyperlink}} />

更新:



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

  BasedOn ={StaticResource MyDefaultHyperlinkStyle}

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

 <样式x:Key =MyDefaultHyperlinkStyleBasedOn ={StaticResource {x:Type Hyperlink}}/> 

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



您可能想要使用 DynamicRe来源,但不幸的是 BasedOn 属性不支持它。



前景属性支持动态资源,所以我们可以在我们的风格中使用相同的技巧。以下是修改为使用动态画笔的测试用户控件:

 < 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>数据导入错误< / TextBlock>
< ItemsControl ItemsSource ={Binding Messages}/>
< / StackPanel>
< / Grid>
< / UserControl>

它按预期工作,即 StackPanel 将是黄色/白色,而在外面它们将是蓝色。



希望这有帮助。


I'm try to set the Foreground colour on a Hyperlink using a Style object in an ancestor's Resources, but it's not having any effect. I even used the BasedOn tip from Changing Hyperlink foreground without losing hover color, but it's not made any difference - I still get a blue hyperlink that is red on hover.

Here's the XAML for my controls, including an ItemsControl whose items are shown using a hyperlink:

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

And the items in the ItemsControl are picking up the following 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>

It's worth noting, too, that I don't want to just set the different colours directly on the Hyperlink in the DataTemplate. This is because the template will be used by a number of different ItemsControl objects, most of which will be on a white background and so can use the standard hyperlink colours. (Note that the one in the XAML above, however, has a red background.)

In short, I don't want the DataTemplate to have to know anything about the control in which it's being used. The styles for the template's controls should just filter down to it.

So... can anyone tell me why the style's not filtering down and what I can do to fix it?

Thanks.

Update:
Since I couldn't get Pavlo's answer to work in my production app, I've since tried it in a separate test app. The app is a WinForms app, with the main form containing nothing but an ElementHost, which itself contains a simple WPF usercontrol. Here's its 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>

As it stands above, this generates an InvalidOperationException, stating "Can only base on a Style with target type that is base type 'IFrameworkInputElement'."

That can be fixed by putting TargetType="Hyperlink" on the Style definition immediately inside the UserControl.Resources element. However, while the messages are being shown, the link part of them still has the default blue hyperlink styling:

In short, it's not working, so I'd welcome any other suggestions/corrections. :(

Update 2:
Thanks to an alternative solution from Pavlo, it now is working. :)

解决方案

After some googling I ran into this post: http://www.11011.net/archives/000692.html.

As it described there, it turns out that elements that are not derived from Control (like TextBlock and Hyperlink) do not look for implicit styles outside the DataTemplate boundary.

Again, as the article says, the possible workaround is to specify the style key explicitly. In your case it might be something like this:

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

Then, you can add an implicit style for Hyperlink that just references our named style in the DataTemplate resources:

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

And because the data template can be used in different places, there is a possibility that parent container doesn't define a style with key "MyDefaultHyperlinkStyle". In this case an exception will be thrown saying that resource "MyDefaultHyperlinkStyle" cannot be found. To address this, you can define a style with such key that will only inherit default style somewhere in App.xaml:

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

Update:

The code you included in your update will not work because of the nature of static resources, which means that the following resource reference in date template...

BasedOn="{StaticResource MyDefaultHyperlinkStyle}"

... will always point to the following resource (which is the default style):

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

Static resource references are resolved at compile time, therefore the closest resource in the tree is used.

You might be tempted to use DynamicResource, but unfortunately it is not supported with the BasedOn property.

BUT, Foreground property supports dynamic resources, so we can use the same trick with brushes we use inside our style. Here is your test user control modified to use dynamic brushes:

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

It works as expected, i.e. all links inside StackPanel will be Yellow/White, while outside they will be blue.

Hope this helps.

这篇关于如何将样式传播到DataTemplate中的超链接?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆