WPF Some styles not applied on DataTemplate controls
Asked Answered
D

4

34

I am trying to learn something about WPF and I am quite amazed by its flexibility.

However, I have hit a problem with Styles and DataTemplates, which is little bit confusing. I have defined below test page to play around a bit with styles etc and found that the Styles defined in <Page.Resources> for Border and TextBlock are not applied in the DataTemplate, but Style for ProgressBar defined in exactly the same way is applied.

Source code (I just use Kaxaml and XamlPadX to view the result)

<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 Border}">
      <Setter Property="Background" Value="SkyBlue"/>
      <Setter Property="BorderBrush" Value="Black"/>
      <Setter Property="BorderThickness" Value="2"/>
      <Setter Property="CornerRadius" Value="5"/>
    </Style>

    <Style TargetType="{x:Type TextBlock}">
      <Setter Property="FontWeight" Value="Bold"/>
    </Style>

    <Style TargetType="{x:Type ProgressBar}">
      <Setter Property="Height" Value="10"/>
      <Setter Property="Width" Value="100"/>
      <Setter Property="Foreground" Value="Red"/>
    </Style>

    <XmlDataProvider x:Key="TestData" XPath="/TestData">
      <x:XData>
        <TestData xmlns="">
          <TestElement>
            <Name>Item 1</Name>
            <Value>25</Value>
          </TestElement>
          <TestElement>
            <Name>Item 2</Name>
            <Value>50</Value>
          </TestElement>
        </TestData>
      </x:XData>
    </XmlDataProvider>

    <HierarchicalDataTemplate DataType="TestElement">
      <Border Height="45" Width="120" Margin="5,5">
        <StackPanel Orientation="Vertical" Margin="5,5" VerticalAlignment="Center" HorizontalAlignment="Center">
          <TextBlock HorizontalAlignment="Center" Text="{Binding XPath=Name}"/>
          <ProgressBar Value="{Binding XPath=Value}"/>
        </StackPanel>
      </Border>
    </HierarchicalDataTemplate>

  </Page.Resources>

  <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
    <StackPanel Orientation="Vertical" VerticalAlignment="Center">
      <Border Height="45" Width="120" Margin="5,5">
        <StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center">
          <TextBlock HorizontalAlignment="Center" Text="Item 1"/>
          <ProgressBar Value="25"/>
        </StackPanel>
      </Border>
      <Border Height="45" Width="120" Margin="5,5">
        <StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center">
          <TextBlock HorizontalAlignment="Center" Text="Item 2"/>
          <ProgressBar Value="50"/>
        </StackPanel>
      </Border>
    </StackPanel>
    <ListBox Margin="10,10"  Width="140" ItemsSource="{Binding Source={StaticResource TestData}, XPath=TestElement}"/>
  </StackPanel>
</Page>

I suspect it has something to do with default styles etc, but more puzzling is why some Styles are applied and some not. I cannot find an easy explanation for above anywhere and thus would like to ask if someone would be kind enough to explain this behaviour in lamens' terms with possible links to technical description, i.e. to MSDN or so.

Thanks in advance for you support!

Darlenedarline answered 19/3, 2010 at 9:59 Comment(0)
S
34

This is actually by design. Elements that do not derive from Control will not pick up implicit Styles, unless they are in the application resources.

This link explains this in more detail, or you can view the Connent bug report.

Serous answered 19/3, 2010 at 18:28 Comment(3)
Thanks for the link! It explains what is going on, but still link to official documentation would be nice just that I know where to look for such things.Darlenedarline
Added link to bug report on Microsoft's Connect site, not sure there is any offical documents that describe this behavior.Serous
both links are dead now. found wayback link for the first one. Please add it to your answer if you like.Tamie
B
39

I discovered a simple workaround for this. For any elements that are not able to search outside the data template encapsulation boundary (i.e. are not being implicitly styled), you can just declare an empty style within the data template for that element type and use the BasedOn attribute of the style to find the correct implicit style outside the data template to apply.

In the example below, the TextBox is able to search outside the data template encapsulation boundary (because it inherits from Control?), but the TextBlock is not able to, so I declare the empty style for it which can search outside the data template.

<ItemsControl.ItemTemplate>
    <DataTemplate>
        <DataTemplate.Resources>
            <Style TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}" />
        </DataTemplate.Resources>
        <DockPanel>
            <TextBlock Text="{Binding Name}"  />
            <TextBox Text="{Binding Value}" />
        </DockPanel>
    </DataTemplate>
</ItemsControl.ItemTemplate>
Binford answered 7/6, 2013 at 1:42 Comment(1)
You're my hero, Brian! Thanks a lot for sharing that.Tisiphone
S
34

This is actually by design. Elements that do not derive from Control will not pick up implicit Styles, unless they are in the application resources.

This link explains this in more detail, or you can view the Connent bug report.

Serous answered 19/3, 2010 at 18:28 Comment(3)
Thanks for the link! It explains what is going on, but still link to official documentation would be nice just that I know where to look for such things.Darlenedarline
Added link to bug report on Microsoft's Connect site, not sure there is any offical documents that describe this behavior.Serous
both links are dead now. found wayback link for the first one. Please add it to your answer if you like.Tamie
L
4

I've looked into this also, and I personally think it's a bug. I've noticed that the style is set if you name your styles like so:

<Style x:Key="BorderStyle" TargetType="{x:Type Border}">
etc...

and explicitly set your DataTemplate to use those styles:

<HierarchicalDataTemplate DataTemplate="TestElement">
  <Border Height="45" Width="120" Margin="5,5", Style="{StaticResource BorderStyle}">

I think that it's possible that for DataTemplates (and maybe ControlTemplates), they default to having a null style, unless you explicitly set them.

That to me is not meant to happen - it's not a logical way of WPF working...

Lightface answered 19/3, 2010 at 12:7 Comment(0)
G
0

This is because ListBox is a logical parent of your datatemplate items, now remember, all properties those are "inheritable" like font, forecolor etc, are derived from the logical parent and ListBox already overrides it in its own default style, thats why this will not work. However in this case, you can use named styles as Mr. Dave has suggested, but I think if it does not work then this is a known problem in case of List Box etc, you can refere to my question here, i had similar problem in listbox, and the answers in my question are in more detail.

Gunar answered 19/3, 2010 at 16:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.