WPF SubControl(如TextBlock)不使用TemplateSelector从窗口继承Style

时间:2014-11-21 09:07:39

标签: c# wpf xaml

我需要帮助,因为我不明白为什么来自datatemplate的控件不会继承窗口资源中定义的样式。 可能有解决方法吗?

如果有人能给我一个解决方案,我会非常感激,因为我花了很多时间找到一些东西。

特此我的例子。例如,horrizontal模板中的Texblock不对齐:

Udapte: 我添加了背景颜色。该样式适用于标签,但不适用于由datatemplate定义的totextblock和textbox。

<Window x:Class="WpfApplication3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:localview="clr-namespace:WpfApplication3"
        Title="MainWindow" Height="350" Width="525">

    <Window.Resources>
        <Style x:Key="{x:Type TextBlock}" TargetType="TextBlock" >
            <Setter Property="Background" Value="Cyan"/>
            <Setter Property="HorizontalAlignment" Value="Left"/>
            <Setter Property="VerticalAlignment" Value="Center"/>
            <Setter Property="Margin" Value="3"/>
            <Setter Property="FontFamily" Value="Comic Sans MS"/>
        </Style>
        <Style x:Key="{x:Type Label}" TargetType="Label">
            <Setter Property="Background" Value="Red"/>
            <Setter Property="VerticalAlignment" Value="Center" />
        </Style>
        <Style x:Key="{x:Type TextBox}" TargetType="TextBox">
            <Setter Property="Background" Value="Cyan"/>
            <Setter Property="HorizontalAlignment" Value="Left"/>
            <Setter Property="VerticalAlignment" Value="Center"/>
            <Setter Property="Margin" Value="3"/>
        </Style>
        <Style x:Key="{x:Type ComboBox}" TargetType="ComboBox">
            <Setter Property="HorizontalAlignment" Value="Left"/>
            <Setter Property="VerticalAlignment" Value="Center"/>
            <Setter Property="Margin" Value="3"/>
        </Style>

        <localview:TemplateSelector x:Key="TemplateSelector">
            <localview:TemplateSelector.DataTemplateH>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Label Content="Value"/>
                        <TextBox Text="{Binding Path=SelectedItem.Content ,ElementName=Combo}"/>
                    </StackPanel>
                </DataTemplate>
            </localview:TemplateSelector.DataTemplateH>
            <localview:TemplateSelector.DataTemplateV>
                <DataTemplate>
                    <StackPanel Orientation="Vertical">
                        <Label Content="Value"/>
                        <StackPanel Orientation="Horizontal">
                            <Label Content="new line"/>
                            **<TextBlock Text="{Binding Path=SelectedItem.Content ,ElementName=Combo}" TextAlignment="Right"/>**
                        </StackPanel>
                    </StackPanel>
                    </DataTemplate>
            </localview:TemplateSelector.DataTemplateV>
        </localview:TemplateSelector>

    </Window.Resources>


    <StackPanel Orientation="Vertical">

        <StackPanel>
            <TextBlock Text="Texblock"/>
            <TextBox Text="Texblock"/>
            <StackPanel Orientation="Horizontal">
                <Label Content="Value"/>
                <ComboBox Name="Combo">
                    <ComboBox.Items>
                        <ComboBoxItem Content="H"/>
                        <ComboBoxItem Content="V"/>
                    </ComboBox.Items>
                </ComboBox>
            </StackPanel>
            <ContentControl  ContentTemplateSelector="{StaticResource TemplateSelector}" 
                                      Content="{Binding Path=SelectedItem.Content ,ElementName=Combo}" />
        </StackPanel>

    </StackPanel>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Reflection;


namespace WpfApplication3
{
    public class TemplateSelector : DataTemplateSelector
    {

        public DataTemplate DataTemplateH
        {
            get;
            set;
        }

        public DataTemplate DataTemplateV
        {
            get;
            set;
        }


        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            string s = (string)item;

            if (s == "H")
                return DataTemplateH;

            if (s == "V")
                return DataTemplateV;

            return base.SelectTemplate(item, container);
        }
    }
}

2 个答案:

答案 0 :(得分:7)

为了阐明为什么 TextBlock找不到它的隐式样式,WPF中有一个奇怪的规则隐式样式只能通过元素跨模板边界继承继承自Control类;不从Control继承的元素不会探测父模板之外的隐式样式。

可以在FrameworkElement

中找到负责此操作的代码
// FindImplicitSytle(fe) : Default: unlinkedParent, deferReference
internal static object FindImplicitStyleResource(
    FrameworkElement fe,
    object resourceKey,
    out object source)
{
    ...

    // For non-controls the implicit StyleResource lookup must stop at
    // the templated parent. Look at task 25606 for further details.
    DependencyObject boundaryElement = null;
    if (!(fe is Control))
    {
        boundaryElement = fe.TemplatedParent;
    }

    ...
}

Carole Snyder在微软explains the reasons for this behavior

  

我给出的原因是控件比元素更明显,并且控件的隐式样式应该应用于任何地方,其中元素的隐式样式不太可能是普遍适用。这个论点是合理的。请考虑以下事项:

     
<StackPanel>
  <StackPanel.Resources> 
    <Style TargetType="TextBlock"> 
      <Setter Property="FontSize" Value="16"/> 
      <Setter Property="Foreground" Value="Green"/> 
    </Style>
  </StackPanel.Resources>

  <TextBlock HorizontalAlignment="Center" Text="Hello!"/> 
  <Button Content="Click me!" Width="200"/> 
  <TextBlock HorizontalAlignment="Center" Text="Please click the button"/>
</StackPanel>
     

Button通过最终创建TextBlock并将字符串添加到TextBlock来显示字符串。如果Button中的TextBlock使用了应用程序定义的隐式样式,则XAML将以这种方式呈现:

     

Example Image

     

这可能不是你想要的行为。另一方面,假设您正在创建一个很酷的UI,并且您希望所有的RepeatButton都具有特定的外观。如果你定义一次RepeatButton的外观,所有RepeatButtons将使用该外观,即使RepeatButton在ControlTemplate中。

答案 1 :(得分:3)

我刚刚尝试了一些简单的演示,是的答案是你不能将模板外部的默认样式应用到一些TextBlock 里面 模板(包括DataTemplate)和ControlTemplate)。这不会发生在其他控件上,例如Label,TextBox(虽然你也说过Style不适用于TextBox,但是我试过它,实际上并非如此)。

要解决此问题,最好的方法是为TextBlock明确设置样式,如下所示:

<TextBlock Text="{Binding Path=SelectedItem.Content ,ElementName=Combo}" 
           TextAlignment="Right" Style="{StaticResource {x:Type TextBlock}}"/>

请注意,正如我所说,只有TextBlocks 模板(DataTemplate和ControlTemplate)才需要。

代码看起来相当荒谬,但它实际上是有效的,没有这样做,因为你认为它不起作用。

相关问题