使用 XAML 将控件添加到 UserControl 中的 ItemsControl

Posted

技术标签:

【中文标题】使用 XAML 将控件添加到 UserControl 中的 ItemsControl【英文标题】:Adding controls to an ItemsControl within a UserControl using XAML 【发布时间】:2017-01-01 14:49:52 【问题描述】:

我想编写一个行为有点像 CommandBar 的控件。 使用 CommandBar 你可以写:

<CommandBar>
    <CommandBar.PrimaryCommands>
        <AppBarButton>B1</AppBarButton>
        <AppBarButton>B2</AppBarButton>
    </CommandBar.PrimaryCommands>
</CommandBar>

我的控件还具有可以在 xaml 中添加控件的属性。 像这样:

<Page
    x:Class="TheApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="using:App27"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="ThemeResource ApplicationPageBackgroundThemeBrush">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <local:MyControl>
            <local:MyControl.LeftStuff>
                <Button>L1</Button>
                <Button>L2</Button>
            </local:MyControl.LeftStuff>
            <local:MyControl.MidStuff>
                <Button>M1</Button>
                <Button>M2</Button>
            </local:MyControl.MidStuff>
            <local:MyControl.RightStuff>
                <Button>R1</Button>
                <Button>R2</Button>
            </local:MyControl.RightStuff>
        </local:MyControl>
    </Grid>
</Page>

到目前为止,我已经想出了以下 UserControl。 MyControl.xaml:

<UserControl
    x:Class="TheApp.MyControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="using:App27"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    d:DesignHeight="300"
    d:DesignWidth="400"
    mc:Ignorable="d">

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <ItemsControl Grid.Column="0" ItemsSource="x:Bind LeftStuff">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
        <ItemsControl Grid.Column="1" ItemsSource="x:Bind MidStuff">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
        <ItemsControl Grid.Column="2" ItemsSource="x:Bind RightStuff">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </Grid>
</UserControl>

MyControl.xaml.cs:

namespace TheApp

    using System.Collections.ObjectModel;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;

    public sealed partial class MyControl: UserControl
    
        public MyControl()
        
            this.InitializeComponent();
        

        public static readonly DependencyProperty LeftStuffProperty =
            DependencyProperty.Register("LeftStuff", typeof(ObservableCollection<FrameworkElement>), typeof(MyControl), new PropertyMetadata(null));

        public ObservableCollection<FrameworkElement> LeftStuff
        
            get  return (ObservableCollection<FrameworkElement>)GetValue(LeftStuffProperty); 
            set  SetValue(LeftStuffProperty, value); 
        

        public static readonly DependencyProperty MidStuffProperty =
            DependencyProperty.Register("MidStuff", typeof(ObservableCollection<FrameworkElement>), typeof(MyControl), new PropertyMetadata(null));

        public ObservableCollection<FrameworkElement> MidStuff
        
            get  return (ObservableCollection<FrameworkElement>)GetValue(MidStuffProperty); 
            set  SetValue(MidStuffProperty, value); 
        

        public static readonly DependencyProperty RightStuffProperty =
            DependencyProperty.Register("RightStuff", typeof(ObservableCollection<FrameworkElement>), typeof(MyControl), new PropertyMetadata(null));

        public ObservableCollection<FrameworkElement> RightStuff
        
            get  return (ObservableCollection<FrameworkElement>)GetValue(RightStuffProperty); 
            set  SetValue(RightStuffProperty, value); 
        
    

这编译并且 MainPage 在设计器中按预期呈现。

但是当我运行代码时,我得到了这个异常:

App27.exe 中出现“Windows.UI.Xaml.Markup.XamlParseException”类型的异常,但未在用户代码中处理 WinRT 信息:无法将“Windows.UI.Xaml.Controls.Button”类型的实例添加到“System.Collections.ObjectModel.ObservableCollection`1”类型的集合中。 [行:16 位置:13] ...

那么有什么问题呢?

【问题讨论】:

【参考方案1】:

自己回答问题:

需要初始化依赖属性,以便 xaml 可以添加元素。

public static readonly DependencyProperty ...StuffProperty =
    DependencyProperty.Register(
        "...Stuff", 
        typeof(ObservableCollection<FrameworkElement>),
        typeof(MyControl),
        // The property needs to be initialized
        new PropertyMetadata(new ObservableCollection<FrameworkElement>())
    );

【讨论】:

以上是关于使用 XAML 将控件添加到 UserControl 中的 ItemsControl的主要内容,如果未能解决你的问题,请参考以下文章

VS2012 - 将WPF现有用户控件添加到项目中

我应该如何将多个控件添加到 WPF 窗口? [复制]

在 App.xaml 中添加按钮并以编程方式将其添加到其他 xaml 页面 Windows 运行时应用

您如何在 WPF 中动态(通过代码)添加在 XAML 中制作的自定义控件?

将 typeof 作为参数传递给来自 xaml 的命令

Xamarin XAML语言教程构建ControlTemplate控件模板