You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET MAUI Windows平台代码创建DataTemplate异常排查

问题

我正尝试为.NET MAUI的CollectionView创建DataTemplate,该实现在Android模拟器上运行正常,但在Windows平台出现问题。

实现步骤:创建Border作为DataTemplate基础,通过代码生成DataTemplate并绑定到CollectionView的ItemTemplate,所有代码位于页面构造函数的try/catch块中,但未触发异常捕获。

MainPage.cs 代码:

AbsoluteLayout mainLayout = new AbsoluteLayout().LoadFromXaml(xaml);

CollectionView collectionViewTest = mainLayout.FindByName<CollectionView>("CollectionViewTest");

Border collectionViewBorderTemplate = new CollectionViewTestBorder();
TapGestureRecognizer tapGesture = new();
tapGesture.Tapped += TapGesture_Tapped;
collectionViewBorderTemplate.GestureRecognizers.Add(tapGesture);

DataTemplate dataTemplate = new() {
    LoadTemplate = () => collectionViewBorderTemplate 
};

collectionViewTest.ItemTemplate = dataTemplate;

ObservableCollection<User> users = new() {
    new User { Name = "Joe", Email = "test@mail.com", Age = 40 },
    new User { Name = "Jane", Email = "test1@mail.com", Age = 50 },
    new User { Name = "James", Email = "test2@mail.com", Age = 35 }
};

collectionViewTest.ItemsSource = users;
BindingContext = vm;

CollectionViewTestBorder.xaml 代码:

<?xml version="1.0" encoding="utf-8" ?>
<Border xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         x:Class="DesignADistance.Components.CollectionViewTestBorder"
         xmlns:models="clr-namespace:DesignADistance.Models"
         x:DataType="models:User">
    <Grid RowDefinitions="100,100,100">
        <Grid.Resources>
            <ResourceDictionary>
                <Style TargetType="Label">
                    <Setter Property="TextColor" Value="PowderBlue"/>
                    <Setter Property="HorizontalTextAlignment" Value="Center"/>
                    <Setter Property="VerticalTextAlignment" Value="Center"/>
                </Style>
            </ResourceDictionary>
        </Grid.Resources>
        <Label Grid.Row="0" Text="{Binding Name}"/>
        <Label Grid.Row="1" Text="{Binding Age}"/>
        <Label Grid.Row="2" Text="{Binding Email}"/>
    </Grid>
</Border>

异常信息:

在Windows运行时,App.g.i.cs中触发空引用异常,异常堆栈信息:

at Microsoft.Maui.Controls.Platform.ItemContentControl.MeasureOverride(Size availableSize)
   at Microsoft.UI.Xaml.FrameworkElement.Microsoft.UI.Xaml.IFrameworkElementOverrides.MeasureOverride(Size availableSize)
   at ABI.Microsoft.UI.Xaml.IFrameworkElementOverrides.Do_Abi_MeasureOverride_0(IntPtr thisPtr, Size availableSize, Size* result)

异常消息:

Object reference not set to an instance of an object.

推测是资源字典初始化异常,请问在Windows平台需要如何调整实现以解决该问题?


解决方案

核心问题原因

当前实现的致命问题是:DataTemplate的LoadTemplate委托返回的是同一个CollectionViewTestBorder实例。CollectionView会为每个Item复用这个单一实例,Android平台可能兼容这种错误用法,但Windows布局系统对控件实例的复用逻辑更严格,会导致控件资源(如ResourceDictionary中的Style)初始化异常,最终触发空引用。

调整步骤

  1. 修改DataTemplate创建逻辑
    不要预先创建CollectionViewTestBorder实例,而是在LoadTemplate委托中每次新建实例,确保每个CollectionView Item拥有独立的控件实例:

    DataTemplate dataTemplate = new() {
        LoadTemplate = () => {
            var border = new CollectionViewTestBorder();
            TapGestureRecognizer tapGesture = new();
            tapGesture.Tapped += TapGesture_Tapped;
            border.GestureRecognizers.Add(tapGesture);
            return border;
        }
    };
    
  2. 可选:将GestureRecognizer移入XAML
    为简化代码,可直接在CollectionViewTestBorder.xaml中添加TapGestureRecognizer,避免在代码中重复创建:

    <Border xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="DesignADistance.Components.CollectionViewTestBorder"
             xmlns:models="clr-namespace:DesignADistance.Models"
             x:DataType="models:User">
        <Border.GestureRecognizers>
            <TapGestureRecognizer Tapped="TapGesture_Tapped"/>
        </Border.GestureRecognizers>
        <!-- 原Grid内容保持不变 -->
    </Border>
    

    然后在CollectionViewTestBorder.xaml.cs中实现TapGesture_Tapped方法,代码更清晰,也能避免跨平台实例复用问题。

  3. 验证资源字典加载
    Windows平台对XAML资源字典的加载时机有要求,通过每次新建实例的方式,能确保每个控件实例都完整初始化XAML中的资源字典和绑定逻辑。

为什么try/catch未捕获异常?

异常是在UI布局线程的后续渲染阶段触发的,并非在构造函数代码执行阶段,所以构造函数中的try/catch无法捕获。可通过全局异常捕获机制(如App.xaml.cs中的UnhandledException事件)捕获这类UI线程异常。


内容的提问来源于stack exchange,提问作者0fail

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 18:34:58