我正在尝试创建“Expander”用户控件,以方便隐藏(折叠)另一个 UI。
现在我有这个:
扩展用户控件 - XAML:
<StackPanel>
<TextBlock Text="{Binding Caption, ElementName=root}"/>
<ToggleButton Content="{Binding ToggleText}" IsChecked="{Binding Expanded}"/>
<ContentControl Visibility="{Binding Expanded, Converter={x:Static root:GlobalConverters.BoolToCollapsedVisibilityConverter}}" Content="{Binding Content, ElementName=root}" />
</StackPanel>
扩展用户控件 - 代码隐藏:
public Expander()
{
InitializeComponent();
DataContext = new ViewModels.ExpanderViewModel();
}
public static readonly DependencyProperty CaptionProperty =
DependencyProperty.Register("Caption", typeof(string), typeof(Expander), new PropertyMetadata("unkown caption"));
public string Caption
{
get => (string)GetValue(CaptionProperty);
set => SetValue(CaptionProperty, value);
}
public new static readonly DependencyProperty ContentProperty =
DependencyProperty.Register("ItemsSource", typeof(object[]), typeof(Expander), new PropertyMetadata(Array.Empty<EmptyContent>()));
public new object[] Content
{
get => (object[])GetValue(ContentProperty);
set => SetValue(ContentProperty, value);
}
扩展器使用 - 查看:
<DataTemplate DataType="{x:Type viewModels:OrdersListModeViewModel}">
<StackPanel>
<controls:Expander Caption="Orders">
<ItemsControl ItemsSource="{Binding Orders}" />
</controls:Expander>
</StackPanel>
</DataTemplate>
我面临两个问题:
正如已经建议的,您必须覆盖
ControlTemplate
,以便控件的客户端可以使用 Content
属性来定义您想要托管的实际内容。然后您只需切换 ContentPresenter
的可见性即可。
要启用自定义,我建议创建一个扩展
HeaderedContentControl
的自定义控件,而不是使用 UserControl
。HeaderedContentControl
为您提供 Header
属性和 Content
属性 - 正是您想要的。
但是,因为已经有一个框架
Expander
控件(也扩展了 HeaderedContentControl
),所以您应该扩展 Expander
并向现有控件添加其他功能:
MyExpander.cs
每个控件绝不能依赖于其数据上下文。控件必须与数据上下文无关。如果您需要外部数据,则必须通过公共依赖属性请求它。内部元素将绑定到这些依赖属性以获取其数据。
这样,控件的客户端就可以完全控制
DataContext
,并且能够通过数据绑定提供所需的数据 - 不会出现任何意外(例如,绑定失败,因为控件内部更改了 DataContext
!)。
class MyExpander : Expander
{
static MyExpander()
{
// You can remove this if you only need to add behavioral functionality
// but want to keep the original visuals and visual states.
FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(
typeof(MyExpander),
new FrameworkPropertyMetadata(typeof(MyExpander)));
}
// TODO::Add new functionality to the existing Expander
}
Generic.xaml
示例模板。仅当从静态构造函数显式覆盖默认样式时才需要。您可以看到
ContentPresenter is collapsed or visible based on the
Expander.IsExpanded` 属性如何:
<Style TargetType="{x:Type local:ExportManagerDialogStyle}">
<Style.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Style.Resources>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ExportManagerDialogStyle}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"
Text="{TemplateBinding Header}" />
<ContenPresenter Grid.Row="1"
Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsExpanded, Converter={StaticResourtce BooleanToVisibilityConverter}}" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
MainWindow.xaml
<Window>
<!-- Either inherit or explicitly set the DataContext -->
<MyExpander DataContext="{ExpanderViewModel}"
Header="Expandable content"
IsExpanded="True">
<ListBox />
</MyExpander>