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

MAUI ListView设SaxonCS XdmValue为ItemsSource时栈溢出咨询

问题背景

我尝试参照WPF ListView 的使用方式操作MAUI ListView:直接向ItemsSource属性赋值实现了IEnumerable接口、且集合内元素重写了ToString方法的对象,期望控件直接展示各元素的ToString()返回结果。

在WPF环境下该方式运行正常,无论数据源是.NET内置类型,还是SaxonCS库中的值,ListView均可正常展示项内容;但在MAUI环境下,该方式仅对简单string[]类型数组生效,当绑定SaxonCS库提供的XdmItem[]或XdmValue类型对象时,程序会抛出无详细堆栈跟踪的StackOverflow异常,仅提示“System.StackOverflowException in System.Private.CoreLib.dll”。

注:所有测试均在Windows平台完成,WPF本身仅支持Windows无需额外说明,本次排查仅关注MAUI的Windows端使用场景;复现问题需要SaxonCS的评估许可证,复现门槛较高。最小复现代码分别包含MAUI版本和WPF版本的工程,仅绑定string[]数组的分支在两个框架下均可正常运行。

可正常运行的WPF示例XAML代码如下:

<Window x:Class="WpfXdmViewTest1.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:local="clr-namespace:WpfXdmViewTest1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <ListView Margin="10" Name="XdmView"></ListView>
    </Grid>
</Window>

对应后台代码如下:

public partial class MainWindow : Window
{
    private static Processor processor = new Processor();
    public MainWindow()
    {
        InitializeComponent();

        //var values = new string[] { "foo", "bar", "baz" };
        //var values = new XdmItem[] { new XdmAtomicValue("foo"), new XdmAtomicValue(3), new XdmAtomicValue(true) };

        var xqueryCompiler = processor.NewXQueryCompiler();
        xqueryCompiler.BaseUri = new Uri("urn:from-string");
        var xqueryExecutable = xqueryCompiler.Compile("(1 to 5) ! <item>Item {.}</item>");
        var xqueryEvaluator = xqueryExecutable.Load();

        var xdmValue = xqueryEvaluator.Evaluate();

        XdmView.ItemsSource = xdmValue;
    }
}

上述WPF代码运行正常,可在ListView中展示每个XdmItem的ToString()结果。

结构几乎一致的MAUI示例XAML代码如下:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MAUIXdmViewTest1.MainPage">

    <ListView x:Name="XdmView"></ListView>
 
</ContentPage>

对应MAUI后台代码如下:

using Saxon.Api;

public partial class MainPage : ContentPage
{
    private static Processor processor = new Processor();

    public MainPage()
    {
        InitializeComponent();

        //var values = new string[] { "foo", "bar", "baz" };
        //var values = new XdmItem[] { new XdmAtomicValue("foo"), new XdmAtomicValue(3), new XdmAtomicValue(true) };

        var xqueryCompiler = processor.NewXQueryCompiler();
        xqueryCompiler.BaseUri = new Uri("urn:from-string");
        var xqueryExecutable = xqueryCompiler.Compile("(1 to 5) ! <item>Item {.}</item>");
        var xqueryEvaluator = xqueryExecutable.Load();

        var xdmValue = xqueryEvaluator.Evaluate();

        XdmView.ItemsSource = xdmValue;
    }
}

上述MAUI代码运行失败,会在System.Private.CoreLib.dll中触发栈溢出异常。


核心原因:WPF与MAUI ListView的ItemsSource处理逻辑差异

两者默认的项模板生成、对象访问逻辑完全不同,这是触发栈溢出的根本原因:

  • WPF的ListView默认项模板逻辑非常简单:当没有自定义ItemTemplate时,会直接调用绑定项的ToString()方法生成文本块展示,不会对绑定对象做额外的反射遍历,哪怕对象本身实现了IEnumerable或者有复杂嵌套属性,也不会递归访问子成员。
  • MAUI的ListView(以及同框架下的CollectionView)默认项模板走的是反射式属性递归遍历逻辑:当绑定项不是.NET原生基础类型(比如string、int这类)时,MAUI会默认尝试反射读取对象的所有公共属性,尝试把复杂对象展开成可展示的结构。如果反射到的属性本身返回的是同类型对象、或者存在循环引用的属性链、或者属性返回的对象依然是复杂可枚举类型,就会无限递归反射下去,最终触发栈溢出。

SaxonCS的XdmValue/XdmItem类型本身就满足触发无限递归的条件:这类XDM对象的属性会返回其他XDM节点/值对象,部分属性甚至存在隐式的循环引用(比如XML节点的Parent属性返回父节点,父节点的Child属性又包含当前节点),MAUI默认反射逻辑撞到这种结构就会无限递归,直接栈溢出。string[]能正常运行是因为string属于MAUI识别的基础类型,不会触发后续反射遍历。


排查&解决思路
  1. 先验证栈溢出根因:不要直接把XdmValue赋值给ItemsSource,先手动把集合转成List<string>,遍历XdmValue逐个调用ToString()把结果存到字符串列表里,再绑定给ListView。如果这种方式运行正常,就可以确认是MAUI默认反射遍历复杂对象导致的递归溢出。
    var displayList = xdmValue.Select(item => item.ToString()).ToList();
    XdmView.ItemsSource = displayList;
    
  2. 不想手动转集合就显式指定ItemTemplate切断反射逻辑:直接给ListView写死最简单的文本项模板,明确告诉MAUI只需要调用ToString()展示文本,不要做额外反射。
    <ListView x:Name="XdmView">
        <ListView.ItemTemplate>
            <DataTemplate>
                <TextCell Text="{Binding}" />
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
    
    这种写法和WPF的默认行为完全对齐,MAUI拿到明确的模板后就不会走默认的复杂对象反射展开逻辑,从根源避免递归。
  3. 如果后续需要展示XdmItem的特定属性,不要依赖默认模板,手动在DataTemplate里绑定需要的具体属性即可,不要让MAUI自行反射解析对象结构。

内容的提问来源于stack exchange,提问作者Martin Honnen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 21:21:26