WPF 样式/模板仅应用于最后添加的元素
本文关键字:最后 添加 元素 应用于 样式 WPF | 更新日期: 2023-09-27 17:55:39
我有一个简单的控件,从ContentControl
派生出以下代码:
public class HeaderFooterControl : ContentControl
{
static HeaderFooterControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(HeaderFooterControl), new FrameworkPropertyMetadata(typeof(HeaderFooterControl)));
}
public object Header
{
get { return (object)GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
// Using a DependencyProperty as the backing store for Header. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.Register("Header", typeof(object), typeof(HeaderFooterControl));
public object Footer
{
get { return (object)GetValue(FooterProperty); }
set { SetValue(FooterProperty, value); }
}
// Using a DependencyProperty as the backing store for Footer. This enables animation, styling, binding, etc...
public static readonly DependencyProperty FooterProperty =
DependencyProperty.Register("Footer", typeof(object), typeof(HeaderFooterControl));
public string HeaderText
{
get { return (string)GetValue(HeaderTextProperty); }
set { SetValue(HeaderTextProperty, value); }
}
// Using a DependencyProperty as the backing store for HeaderText. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HeaderTextProperty =
DependencyProperty.Register("HeaderText", typeof(string), typeof(HeaderFooterControl));
public string FooterText
{
get { return (string)GetValue(FooterTextProperty); }
set { SetValue(FooterTextProperty, value); }
}
// Using a DependencyProperty as the backing store for FooterText. This enables animation, styling, binding, etc...
public static readonly DependencyProperty FooterTextProperty =
DependencyProperty.Register("FooterText", typeof(string), typeof(HeaderFooterControl));
}
它具有可自定义的页眉和页脚属性,因此用户可以在其中附加任何控件。
此应用程序中唯一定义的窗口如下所示:
<Window x:Class="CustomControlTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CustomControlTest"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="{x:Type local:HeaderFooterControl}" x:Key="DefaultHeaderFooterStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:HeaderFooterControl}">
<Grid Background="Pink">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<ContentPresenter Content="{Binding Header, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"/>
<ContentPresenter Grid.Row="1"/>
<ContentPresenter Content="{Binding Footer, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" Grid.Row="2"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type local:HeaderFooterControl}" BasedOn="{StaticResource DefaultHeaderFooterStyle}">
<Style.Setters>
<Setter Property="Header">
<Setter.Value>
<TextBlock Text="{Binding HeaderText, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:HeaderFooterControl}}}" Background="Yellow" HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
</Setter.Value>
</Setter>
<Setter Property="Footer">
<Setter.Value>
<TextBlock Text="{Binding FooterText, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:HeaderFooterControl}}}" Background="Green" HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<local:HeaderFooterControl HeaderText="H1" FooterText="F1" Margin="10"/>
<local:HeaderFooterControl HeaderText="H2" FooterText="F2" Grid.Row="1" Margin="10"/>
<local:HeaderFooterControl HeaderText="H3" FooterText="F3" Grid.Row="2" Margin="10"/>
</Grid>
</Window>
此窗口的资源为我的自定义控件定义了 2 种样式。自定义控件显示页眉、主要内容和页脚。默认情况下,页眉/页脚TextBlock
,其Text
属性绑定到HeaderText
或FooterText
HeaderFooterControl
的属性。问题是只有最后添加的HeaderFooterControl
显示任何内容。为什么会这样?
到目前为止,我找到的唯一解决方案是将页眉和页脚部分的内容移动到资源中,然后使用StaticResource
扩展从 xaml 代码中引用这些资源。所有内容都是UIElement
的,因此每个实例都应该设置x:Shared="False"
属性,以便每次在可视化树中需要时都会创建它。另请查看此答案,它暗示了 https://stackoverflow.com/a/8702180/371967 描述的相同行为
<Window x:Class="CustomControlTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CustomControlTest"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="{x:Type local:HeaderFooterControl}" x:Key="DefaultHeaderFooterStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:HeaderFooterControl}">
<Grid Background="Pink">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<ContentPresenter Content="{Binding Header, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"/>
<ContentPresenter Grid.Row="1"/>
<ContentPresenter Content="{Binding Footer, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" Grid.Row="2"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<TextBlock x:Key="DefaultHeaderContent" Text="{Binding HeaderText, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:HeaderFooterControl}}}" Background="Yellow" HorizontalAlignment="Stretch" VerticalAlignment="Center" x:Shared="False"/>
<TextBlock x:Key="DefaultFooterContent" Text="{Binding FooterText, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:HeaderFooterControl}}}" Background="Green" HorizontalAlignment="Stretch" VerticalAlignment="Center" x:Shared="False"/>
<Style TargetType="{x:Type local:HeaderFooterControl}" BasedOn="{StaticResource DefaultHeaderFooterStyle}">
<Style.Setters>
<Setter Property="Header" Value="{StaticResource DefaultHeaderContent}"/>
<Setter Property="Footer" Value="{StaticResource DefaultFooterContent}"/>
</Style.Setters>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<local:HeaderFooterControl HeaderText="H1" FooterText="F1" Margin="10"/>
<local:HeaderFooterControl HeaderText="H2" FooterText="F2" Grid.Row="1" Margin="10"/>
<local:HeaderFooterControl HeaderText="H3" FooterText="F3" Grid.Row="2" Margin="10"/>
</Grid>
</Window>