【问题标题】:get child nodes of node WPF获取节点 WPF 的子节点
【发布时间】:2021-12-29 04:31:48
【问题描述】:

我已经创建了这个用户控件

    public partial class Dropdown : UserControl
    {
        public string Title { get; set; } = string.Empty;
        private void loadSuccess(object sender, RoutedEventArgs e)
        {
            TitleBlock.Text = Title;
        }
        public Dropdown() 
        {
            Loaded += loadSuccess;
            InitializeComponent();
        }
    }
<UserControl x:Class="Lamprey.UserControls.Dropdown"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Lamprey.UserControls"
             mc:Ignorable="d" 
>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="17"></ColumnDefinition>
            <ColumnDefinition Width="*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
        </Grid.RowDefinitions>
        <TextBlock Text=">" Grid.Row="0" Grid.Column="0" Foreground="#FFC7C7C7"></TextBlock>
        <TextBlock x:Name="TitleBlock" Grid.Row="0" Grid.Column="1"></TextBlock>
        <ListBox x:Name="Items" Grid.Column="1" Grid.Row="1" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="White">
            <ListBox.ItemContainerStyle>
                <Style TargetType="{x:Type ListBoxItem}">
                    <Setter Property="Focusable" Value="False"/>
                </Style>
            </ListBox.ItemContainerStyle>
        </ListBox>
    </Grid>
</UserControl>

本来就是这样用的

                <usercontrols:Dropdown Title="History">
                    <ListBoxItem>
                        <TextBlock>Example</TextBlock>
                    </ListBoxItem>
                </usercontrols:Dropdown>

我想弄清楚如何获取&lt;Dropdown&gt; 的子项列表,以便将它们移动到项目&lt;ListBox&gt;

最终目标是让添加到&lt;Dropdown&gt; 的所有子项自动添加到&lt;ListBox&gt; 命名项。这样,整个列表框可以在下拉菜单关闭时隐藏,在下拉菜单打开时显示。

【问题讨论】:

  • 你的下拉菜单应该继承 ItemsControl 而不是 UserControl
  • 为什么不直接将 ListBox 与 ControlTemplate 一起使用?

标签: c# wpf xaml


【解决方案1】:

关键是定义一个集合依赖属性并将其绑定到ListBox。必须将此属性声明为控件的内容属性,以便能够在 XAML 中隐式添加项目。

  1. 定义自定义非泛型集合或使用现有集合

DropDownItemCollection.cs

public class DropDownItemCollection : List<object>
{ }
  1. 定义非泛型集合类型的依赖属性
  2. 将此属性声明为内容属性,使用ContentProperty 属性装饰属性所有者
  3. (可选)定义DataTemplate 类型属性,例如ItemTemplate,以允许使用显式DataTemplate 对项目进行模板化

DropDown.xaml.cs

[ContentProperty(nameof(DropDown.DropDownItems))]
public partial class DropDown : UserControl
{
  public DropDownItemCollection DropDownItems
  {
    get => (DropDownItemCollection)GetValue(DropDownItemsProperty);
    set => SetValue(DropDownItemsProperty, value);
  }

  public static readonly DependencyProperty DropDownItemsProperty =
    DependencyProperty.Register(
      "DropDownItems",
      typeof(DropDownItemCollection),
      typeof(DropDown),
      new PropertyMetadata(default));

  public DataTemplate ItemTemplate
  {
    get => (DataTemplate)GetValue(ItemTemplateProperty);
    set => SetValue(ItemTemplateProperty, value);
  }

  public static readonly DependencyProperty ItemTemplateProperty =
    DependencyProperty.Register(
      "ItemTemplate",
      typeof(DataTemplate),
      typeof(DropDown),
      new PropertyMetadata(default));


  public DropDown()
  {
    InitializeComponent();
    this.DropDownItems = new DropDownItemCollection();
  }
}
  1. 将内部ListBox 绑定到新的DropDownItems 属性

DropDown.xaml

<UserControl>
  <ListBox ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=DropDownItems}"
           ItemTemplate="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=ItemTemplate}" />
</UserControl>

示例

<!-- 
  Since the collection is of type object you can add anything to the collection.
  The ItemTemplate property allows to explicitly template the item layout.
-->
<Window>
  <Window.Resources>
    <DataTemplate x:Key="DroptDownItemTemplate">
      <Grid>
        <Border Background="OrangeRed" />
        <TextBlock Text="{Binding}" />
      </Grid>
    </DataTemplate>
  </Window.Resources>

  <DropDown ItemTemplate={StaticResource DroptDownItemTemplate}">
    <sys:String>Item 1</sys:String>
    <sys:String>Item 2</sys:String>
  </DropDown>
</Window>

备注
在扩展 ListBox 而不是 UserControl 时,您可以跳过所有这些。这样做,您的控件将支持在 XAML 中创建项目和开箱即用的模板。
隐藏和显示内部ListBox 会导致布局发生变化,从而导致难看的内容调整大小。您应该考虑在Popup 内托管ListBox(或者在扩展ListBox 的情况下ItemsPresenter)以创建覆盖而不是调整大小的浮出控件。

【讨论】:

    猜你喜欢
    • 2015-05-14
    • 2013-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多