【问题标题】:Allowing to add elements to a list in xaml允许将元素添加到 xaml 中的列表
【发布时间】:2026-02-09 16:20:06
【问题描述】:

我创建了一个自定义控件,我使用以下代码插入到我的窗口中

<controls:ListExpander Text="Class Diagrams"></controls:ListExpander>

有问题的控件包含几个子控件,其中包括一个列表。如何创建设置,以便我可以指定应添加到列表中的项目?最终我正在寻找以下架构

<controls:ListExpander Text="Class Diagrams">
  <SomeItem>data<SomeItem>
  <SomeItem>data<SomeItem>
  <SomeItem>data<SomeItem>
  <SomeItem>data<SomeItem>
</controls:ListExpander>

在这种情况下,应该将 SomeItem 对象添加到 ListExpander 的列表中:

    <ListBox Name="lstItems" Background="LightGray">
        <ListBox.Items>
            // Items should go here
        </ListBox.Items>
    </ListBox>

我对 WPF 很陌生,但我想这类似于在 ListExpander 上创建一个依赖集合,该集合采用 SomeItem 类型的对象?

编辑:让我澄清一下。我只是希望能够给控件一些参数,它可以将其转换为控件中包含的列表框中的项目。

【问题讨论】:

    标签: c# .net wpf xaml


    【解决方案1】:

    您是否为 ListExpander 创建了类?您可以非常简单地继承 ItemsControl 的所有功能。这是我为您创建的示例类,用于建模。

    using System.Windows.Controls;
    
    namespace ListExpanderSample
    {
        public class ListExpander : ItemsControl
        {
            static ListExpander()
            {
                /* Required logic goes here */
            }
        }
    }
    

    实施

    <Grid>
        <Grid.Resources>
            <Style x:Key="{x:Type local:ListExpander}" TargetType="{x:Type local:ListExpander}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type local:ListExpander}">
                            <Border Background="Transparent" >
                                <ScrollViewer Focusable="False" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
                                    <ItemsPresenter />
                                </ScrollViewer>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Grid.Resources>
        <local:ListExpander>
            <local:ListExpander.Items>
                <Button Content="Button 1"/>
                <TextBox Text="TextBox 1"/>
                <Button Content="Button 2"/>
                <TextBox Text="TextBox 2"/>
            </local:ListExpander.Items>
        </local:ListExpander>
    </Grid>
    

    屏幕截图

    Sample ListExpander http://lh4.ggpht.com/_jvamiP47SsA/SsWM6xN_3BI/AAAAAAAAAkg/tZUWxzi9wVI/s800/Window1.jpg

    我希望这对你有所帮助,Qua。

    【讨论】:

      【解决方案2】:

      我假设您的控件不仅包含您要添加的这些子项,对吗?所以我会像这样向你的控件类添加一个属性:

      private ObservableCollection<UIElement> _items = new ObservableCollection<UIElement>();
      public ObservableCollection<UIElement> Items
      {
          get { return this._items; }
      }
      

      然后在您的控件模板中,您只需将列表框绑定到此集合

      <ListBox Name="lstItems" Background="LightGray" ItemsSource="{Binding Items}">
      </ListBox>
      

      这样你就可以像这样使用它:

      <controls:ListExpander Text="Class Diagrams">
        <controls:ListExpander.Items>
          <SomeItem>data<SomeItem>
          <SomeItem>data<SomeItem>
          <SomeItem>data<SomeItem>
          <SomeItem>data<SomeItem>
        </controls:ListExpander.Items>
      </controls:ListExpander>
      

      为了能够在没有&lt;controls:ListExpander.Items&gt; 的情况下使用它,用[ContentProperty("Items")] 属性装饰你的类。

      【讨论】:

      • Items 和 lstItems 之间的绑定似乎不起作用。 SomeItem 对象实际上是添加到 _items 中的,而不是列表框。
      • 也许您需要在控件构造函数中设置 DataContext 才能使绑定起作用。像这样的东西。DataContext = this;或者使用 TemplateBinding 而不是 Binding,或者使用更长版本的 Binding 表达式来指定 RelativeSource。无论如何,原则是站得住脚的,你只需要在我的示例代码中找到一个缺失的怪癖。
      【解决方案3】:

      有一个简单的方法来做到这一点。将 ItemCollection 类型的属性添加到您的控件类,如下所示:

      public ItemCollection Items{
          get{
              return innerItems.Items;
          }set{
              innerItems.Items.Clear();
              foreach (var item in value){
                  innerItems.Items.Add(item);
              }
          }
      }
      

      innerItems 只是 XAML 中的一个 ItemsControl(像这样):

      <UserControl x:Class="TestApp.ItemsExtender"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          Height="300" Width="300">
          <StackPanel>
              <Label Content="Control Label" />
              <ItemsControl x:Name="innerItems" />
          </StackPanel>
      </UserControl>
      

      然后像这样向你的控件类添加一个属性:

      [ContentProperty("Items")]
      public partial class ItemsExtender : UserControl
      {...}
      

      这将告诉 XAML 应将默认项分配给您的 Items 属性,并且您的 Items 属性将使用它们来填充您的内部列表集合。然后你可以像这样消费它:

      <this:ItemsExtender>
          <Label Content="item1" />
          <Label Content="item2" />
          <Label Content="item3" />
      </this:ItemsExtender>
      

      您可以使用类型转换器扩展此示例以支持将任意内容添加到集合和依赖属性以支持绑定,但这应该可以帮助您入门。

      希望对你有帮助!

      【讨论】:

        最近更新 更多