ContentPresenter в ControlTemplate не может изменить прикрепленное свойство зависимости

Почему следующий упрощенный код не устанавливает размер шрифта TextBlock равным 50?

<Window.Resources>
    <ControlTemplate TargetType="ContentControl" x:Key="Test">
        <ContentPresenter TextBlock.FontSize="50" />
    </ControlTemplate>        
</Window.Resources>        
<Grid>
    <ContentControl Template="{StaticResource Test}">
        <TextBlock>Test should be rendered big</TextBlock>
    </ContentControl>                   
</Grid>

Если я изменю значение свойства FontSize, Visual Studio покажет мне текст нужного размера. После компиляции или выполнения приложения размер текстового блока всегда сбрасывается до размера по умолчанию.

Я также тестировал различные версии со стилями и встроенными ресурсами, но всегда оказывался в ситуации, когда я не могу установить наследование прикрепленных dp из ControlTemplate, содержащего ContentPresenter. Это по дизайну?


person HCL    schedule 17.06.2010    source источник
comment
Никогда раньше не было такой ситуации, но может быть по замыслу. Я думаю, что ContentPresenter просто заменяет себя контентом, который вы ему предоставляете.   -  person decyclone    schedule 17.06.2010


Ответы (3)


Я нашел причину такого поведения - это по дизайну:

Если содержимое ContentControl уже является элементом WPF, оно создается перед использованием в ContenPresenter. Логическим родителем элемента является, следовательно, ContentControl. Я могу проверить это, изменив разметку ContentControl на следующее:

<ContentControl Template="{StaticResource Test}" TextBlock.FontSize="50">                
    <TextBlock>
            This text now is shown with a size of 50
    </TextBlock>                    
</ContentControl>

В этом примере размер текста 50 по желанию. Я могу доказать эту аргументацию также с помощью wpf-visualizer Visual Studio. Родителем является ContentControl и через dp-наследование FontSize берется из родителя (ContentControl), а текст показывается размером 50!

Другое поведение можно наблюдать, если ContentControl содержит только текст в качестве содержимого:

<Window.Resources>
    <ControlTemplate x:Key="Test"  TargetType="{x:Type ContentControl}">
        <ContentPresenter  TextBlock.FontSize="50"/>
    </ControlTemplate>
</Window.Resources>                
<Grid>
    <ContentControl Template="{StaticResource Test}">                
        This text is shown with a size of 50
    </ContentControl>
</Grid>

В этом сценарии TextBox создается с помощью ContentPresenter, поскольку текст нельзя ввести в визуальное дерево. Текстовое поле не имеет родителя, но свойство TemplateParent ведет к ContentPresenter в качестве родителя TextBox, а система DP принимает значение FontSize через присоединенное наследование свойства зависимости от ContentPresenter. Вот почему в этом сценарии размер шрифта изменен на 50.

Различные сценарии описаны здесь.

Чего я не понимаю, так это почему VS2010 показывает FontSize 50 перед компиляцией.

person HCL    schedule 18.06.2010

Как насчет :

<Window.Resources>
    <ControlTemplate TargetType="ContentControl"
                     x:Key="Test">
        <Border TextBlock.FontSize="50">
            <ContentPresenter />
        </Border>
    </ControlTemplate>
</Window.Resources>
<Grid>
    <ContentControl Template="{StaticResource Test}">
        <TextBlock>Test should be rendered big</TextBlock>
    </ContentControl>
</Grid>
person decyclone    schedule 17.06.2010
comment
Я скопировал его прямо из моего редактора кода после того, как увидел, что он работает! - person decyclone; 17.06.2010
comment
Вы его скомпилировали и запустили? Когда я копирую код в редакторе, он работает. После компиляции не получается. Я тестировал его под .net 3.51, а теперь и под .net 4, та же проблема. - person HCL; 17.06.2010

Это интересно, потому что я заставил что-то вроде этого работать. Есть ли разница?

<Style x:Key="SingleWaveItemContainerStyle" TargetType="{x:Type ListBoxItem}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ListBoxItem}">
                    <Grid Background="{StaticResource WindowBackgroundColor}">
                        <Border Width="125" x:Name="BorderItem" Height="60" Margin="5" BorderThickness="2" ClipToBounds="True" BorderBrush="{StaticResource ViperPanelBorderColor}" Style="{StaticResource ButtonBorderStyle}">
                            <Rectangle x:Name="BackgroundRec" Fill="{StaticResource ViperPanelBorderColor}" Stroke="Transparent" Width="125" Height="60" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                        </Border>
                        <ContentPresenter Name="TheContentPresenter" Width="115" Height="60" Margin="5" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                    </Grid>

                    <ControlTemplate.Triggers>
                        <Trigger Property="IsSelected" Value="true">
                            <Setter TargetName="BorderItem" Property="BorderBrush" Value="{StaticResource NavBar_HighlightBrush}"/>
                            <Setter TargetName="BackgroundRec" Property="Fill" Value="{StaticResource NavBar_HighlightBrush}"/>
                            <Setter TargetName="TheContentPresenter" Property="TextElement.Foreground" Value="White"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>



    <DataTemplate x:Key="SingleWaveDataTemplate" DataType="ListBoxItem">
        <StackPanel>
            <StackPanel Orientation="Horizontal">

                <TextBlock FontWeight="Bold" Text="{Binding Name, Mode=OneWay}" Width="{Binding ElementName=this, Path=Content.DesiredWidth}"/>
            </StackPanel>
            <StackPanel Orientation="Horizontal">

                <TextBlock FontSize="8" Text="{Binding CreationDate, Mode=OneWay}" Width="{Binding ElementName=this, Path=Content.DesiredWidth}"/>
            </StackPanel>
        </StackPanel>
    </DataTemplate>

На странице xaml у меня есть:

<ListBox Background="Transparent" ItemTemplate="{StaticResource SingleWaveDataTemplate}" ItemContainerStyle="{StaticResource SingleWaveItemContainerStyle}" BorderThickness="0" ItemsSource="{Binding AllModes, Mode=OneWay}" Height="{Binding ElementName=this, Path=Parent.Height}" SelectedItem="{Binding CurrentSingleWaveModeViewModel, Mode=TwoWay}">
                    <ListBox.ItemsPanel>
                        <ItemsPanelTemplate>
                            <StackPanel Height="{Binding ElementName=Parent, Path=Height}" Background="{StaticResource WindowBackgroundColor}"/>
                        </ItemsPanelTemplate>
                    </ListBox.ItemsPanel>
                </ListBox>

Возможно, мы ДОЛЖНЫ использовать шаблоны данных, чтобы получить желаемый эффект?

person Mike Bynum    schedule 12.08.2010
comment
Дох, очевидно, почему это работает. Текстовый блок размещается шаблоном данных. что означает, что любое влияние на шаблон управления приведет к тому, что это сработает. - person Mike Bynum; 13.08.2010