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

TFF*_*FFR 4 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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Mik*_*bel 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;
    }

    ...
}
Run Code Online (Sandbox Code Playgroud)

微软的Carole Snyder 解释了这种行为的原因:

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

<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>
Run Code Online (Sandbox Code Playgroud)

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

示例图像

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


Kin*_*ing 4

我刚刚尝试了一些简单的演示,是的,答案是您不能将模板外部某处定义的默认样式应用到模板内部的某些 TextBlock(包括 DataTemplate 和 ControlTemplate)。其他控件如Label、TextBox则不会出现这种情况(虽然你也说Style不适用于TextBox,但我尝试了一下,实际上并非如此)。

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

<TextBlock Text="{Binding Path=SelectedItem.Content ,ElementName=Combo}" 
           TextAlignment="Right" Style="{StaticResource {x:Type TextBlock}}"/>
Run Code Online (Sandbox Code Playgroud)

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

该代码看起来相当荒谬,但它确实有效,如果不这样做,你会发现它不会工作。