为建立中文知识库加块砖 ——中科大胡不归
问题描述
HeaderedContentControl
是一个高度类似GroupBox
的WPF组件。我们要实现点击Header,隐藏和显示Content的效果。
先看效果
问题分析
原生的HeaderedContentControl
并不支持我们的需求,所以我们需要继承它并响应点击事件。在用户点击时,将Content的Visibility由Visible
设置为Collapsed
。对目前的我,最大的难点是如何在自定义控件里面访问子控件。
解决方案
通过参考文章中的方法,控件+模板的配合实现。
定义模板
<Style TargetType="control:MyHeaderedContentControl">
<!-- 此处的Margin的bottom是针对下个同级Control的 -->
<Setter Property="Margin" Value="0,0,0,0" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="control:MyHeaderedContentControl">
<StackPanel>
<!-- Header -->
<StackPanel Orientation="Horizontal" Margin="13,6,0,6" Height="40">
<TextBlock Width="6" Background="{DynamicResource SystemControlBackgroundAccentBrush}"/>
<TextBlock Text="{TemplateBinding Header}" FontSize="14" Foreground="{DynamicResource SystemControlForegroundBaseHighBrush}"
Style="{DynamicResource BaseTextBlockStyle}"
HorizontalAlignment="Center" VerticalAlignment="Center"
Margin="6,0,0,0"/>
</StackPanel>
<!-- Content -->
<ContentPresenter x:Name="PART_Content" Content="{TemplateBinding Content}"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
定义Control
[TemplatePart(Name = "PART_Content", Type = typeof(ContentPresenter))]
public class MyHeaderedContentControl : HeaderedContentControl
{
private ContentPresenter _contentPresenter;
public static readonly DependencyProperty ClickToHideProperty =
DependencyProperty.Register("ClickToHide", typeof(bool), typeof(MyHeaderedContentControl),
new PropertyMetadata(null));
public bool ClickToHide
{
get => (bool)GetValue(ClickToHideProperty);
set => SetValue(ClickToHideProperty, value);
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_contentPresenter = GetTemplateChild("PART_Content") as ContentPresenter;
}
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnPreviewMouseLeftButtonDown(e);
// Only a click on this control is handled, not children.
if (_contentPresenter is null || !e.Source.Equals(this))
return;
// If the child (Content) is visible, collapse it, if it is collapsed, make it visible.
_contentPresenter.Visibility = _contentPresenter.Visibility == Visibility.Collapsed
? Visibility.Visible : Visibility.Collapsed;
e.Handled = true;
}
}
实例引用
<Grid>
...
<control:MyHeaderedContentControl Header="管理通知"
VerticalAlignment="Top"
ClickToHide="True"
Grid.Row="0" >
...
</Grid>