WinUI3:如何在XAML中向集合属性添加自定义控件?排查报错
问题原因
出现Error XHR0015的核心原因是CustomControl1的Items依赖属性对应的ObservableCollection未预先实例化。在XAML解析过程中,当尝试向Items集合添加CustomControl2实例时,集合对象还处于null状态,WPF无法将元素添加到不存在的集合中,因此抛出该错误。
正确实现方式
要解决这个问题,需要确保Items集合在XAML解析前已经完成实例化,有两种可行的实现方式:
方式1:在依赖属性元数据中设置默认实例
注册Items依赖属性时,直接在PropertyMetadata中传入一个新的ObservableCollection<CustomControl2>实例作为默认值,确保控件被创建时集合就存在。
方式2:在CustomControl1的构造函数中初始化集合
在控件的构造函数里手动实例化Items集合,同样能保证XAML解析时集合已就绪。
完整代码示例
CustomControl1 后台代码
using System.Collections.ObjectModel; using System.Windows; using System.Windows.Controls; namespace YourNamespace { public class CustomControl1 : Control { // 方式1:依赖属性元数据设置默认实例 public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register( nameof(Items), typeof(ObservableCollection<CustomControl2>), typeof(CustomControl1), new PropertyMetadata(new ObservableCollection<CustomControl2>())); public ObservableCollection<CustomControl2> Items { get => (ObservableCollection<CustomControl2>)GetValue(ItemsProperty); set => SetValue(ItemsProperty, value); } // 方式2:构造函数初始化(注释掉方式1的元数据默认值,启用这段代码即可) // public CustomControl1() // { // Items = new ObservableCollection<CustomControl2>(); // } static CustomControl1() { DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1))); } } }
CustomControl2 后台代码
using System.Windows; using System.Windows.Controls; namespace YourNamespace { public class CustomControl2 : Control { static CustomControl2() { DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl2), new FrameworkPropertyMetadata(typeof(CustomControl2))); } } }
控件模板(Generic.xaml)
CustomControl1 的模板
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:YourNamespace"> <Style TargetType="{x:Type local:CustomControl1}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:CustomControl1}"> <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> <!-- 通过TemplatedParent绑定到Items集合 --> <ItemsControl ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Items}"/> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style>
CustomControl2 的模板
<Style TargetType="{x:Type local:CustomControl2}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:CustomControl2}"> <!-- 红色边框模板 --> <Border BorderBrush="Red" BorderThickness="1" Margin="2" Padding="4"/> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary>
最终XAML使用代码(与原代码一致,现在可正常运行)
<Window x:Class="YourNamespace.MainWindow" 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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:myControls="clr-namespace:YourNamespace" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <myControls:CustomControl1> <myControls:CustomControl1.Items> <myControls:CustomControl2></myControls:CustomControl2> <myControls:CustomControl2></myControls:CustomControl2> <myControls:CustomControl2></myControls:CustomControl2> </myControls:CustomControl1.Items> </myControls:CustomControl1> </Grid> </Window>
内容的提问来源于stack exchange,提问作者Daniele Pugliese
相关产品推荐
相关产品推荐

