WPF:如何创建呈现作为内容传递的控件的 UserControl

问题描述 投票:0回答:1

我正在尝试创建“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>

我面临两个问题:

  1. 设计师正在显示此错误屏幕: 我尝试删除 obj 和 bin 目录,但没有帮助。

  2. 我在 Expander.xaml 中遇到绑定错误:
    我不明白为什么“controls:Expander”元素内容不使用自己的数据上下文

wpf mvvm user-controls
1个回答
0
投票

正如已经建议的,您必须覆盖

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>
© www.soinside.com 2019 - 2024. All rights reserved.