WTF of WPF [Part One]- Templating & Styling

|

Have you ever been bugged by WPF's strange behaviour for a long time and cannot stop asking:"WTF?".  Douglas Stockwell just met one of those confusing aspects of WPF, I just generalize his confusion about WPF's templating and styling into the following XAML repro code:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <
Page.Resources>
        <
Style TargetType="{x:Type TextBlock}">
            <
Setter Property="TextElement.Foreground" Value="Cyan"/>
        </
Style>
        <
Style TargetType="{x:Type ContentPresenter}">
            <
Setter Property="TextElement.Foreground" Value="Cyan"/>
        </
Style>
        <
Style TargetType="{x:Type  AccessText}">
            <
Setter Property="TextElement.Foreground" Value="Cyan"/>
        </
Style>
        <
Style TargetType="{x:Type Rectangle}">
            <
Setter Property="Fill" Value="Cyan"/>
        </
Style>
        <
Style TargetType="{x:Type Image}">
            <
Setter Property="Source" Value="C:\WINDOWS\Web\Wallpaper\Home.jpg"/>
        </
Style>
        <
Style TargetType="{x:Type MediaElement}">
            <
Setter Property="Source" Value="C:\WINDOWS\clock.avi"/>
        </
Style>
        <
Style TargetType="{x:Type InkCanvas}">
            <
Setter Property="Background" Value="Cyan"/>
        </
Style>
        <
Style TargetType="{x:Type Border}">
            <
Setter Property="BorderThickness" Value="10"/>
            <
Setter Property="BorderBrush" Value="Cyan"/>
        </
Style>
        <
Style TargetType="{x:Type StackPanel}">
            <
Setter Property="Background" Value="Green"/>
        </
Style>
        <
Style TargetType="{x:Type Control}">
            <
Setter Property="Template">
                <
Setter.Value>
                    <
ControlTemplate>
                        <
Label>Inside Control</Label>
                    </
ControlTemplate>
                </
Setter.Value>
            </
Setter>
        </
Style>
        <
ControlTemplate x:Key="template">
            <!--
WTF, StackPanel, TextBlock, AccessText, ContentPresenter, InkCanvas,  Image, Rectangle,
              MediaElement etc cannot pick up their respective implicit styles here,
              one takeway from this empircal discovery is that Elements directly derived from FramworkElement cannot work in this scenario.
-->
            <
StackPanel>
                <
TextBlock Name="tb">inside TextBlock</TextBlock>
                <
AccessText>inside AccessText</AccessText>
                <
ContentPresenter>
                    <
ContentPresenter.Content>
                    inside ContentPresenter
                    </ContentPresenter.Content>
                </
ContentPresenter>
                <
InkCanvas/>
                <
Image/>
                <
Rectangle Width="40" Height="40"/>
                <
MediaElement/>
                <!--
WTF, Border can pick up implicit style here.-->
                <
Border Width="40" Height="40"/>
                <!--
WTF, Control can pick up implicit style here, since Border and Control can work here, our previous hypothesis breaks.-->
                <
Control/>
            </
StackPanel>
        </
ControlTemplate>
    </
Page.Resources>
    <
Control Template="{StaticResource template}"/>
</
Page>

When you have above XAML code runnning in XAMLPad, you will see that StackPanel((or other Panel derivatives), TextBlock, AccessText, ContentPresenter, InkCanvas, Image, Rectangle(or other Shape derivatives), MediaElement et al cannot pick up the implicit styles, well, this gives us an empirical understanding that elements directly derived from FrameworkElement cannot pick up implicit styles when placed inside FrameworkTemplate(DataTemplate, ControlTemplate, ItemsPanelTemplate), but how about Border and Control, those two privileged guys works quite different from their siblings, Anyway, Control derivatives(including Control itself) all work pretty well in this scenario. so question comes, why those aforementioned elements aren't created equal? Can we perceive this aspect of WPF as another example of breaking the principle of consistency.

Edit: Thanks for Doug's great find, if you look at the implementation of System.Windows.FrameworkElement.FindImplicitStyleResource() method from reflector, you will find that if the elements aren't Controls or Control derivatives, style lookup is limited within the templated parent boundary(In my example, the templated parent is Control), and as to the Border, the Border within the template still cannot pick up its implict style, but since Page's template has Border defined there, and in the Page case, Page is the templated parent, so the implicit style in Page's resources is within the search boundary for Border, so the Border can pick up the style there, to put it simple: the resolution of non-Control element's implicit style are limited within its templated parent boundary.

But still, my confusion remains, why the logic of style lookup works the way it is now, why grant Controls more privileges than other equal citizens of WPF?

0 comments: