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

填充WinUI-3 ListView时出现无法捕获的异常(0xc000027b)

问题

将List<Windows.ApplicationModel.Package>作为ItemsSource填充ListView(或ItemsView)时,控件偶尔会崩溃;当使用Package.Logo作为Image的源时,崩溃概率显著升高。

预期效果是触发控件后显示所有已安装应用及其图标等内容,初始加载时能成功显示,但滚动列表时会触发崩溃。


用到的代码

XAML代码

<ContentDialog
    x:Class="Program.AllAppsList"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="TITLE"
    Style="{ThemeResource DefaultContentDialogStyle}">
    <Grid>
        <ListView ItemsSource="{x:Bind Packages}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <!-- 取消注释后崩溃概率大幅上升 -->
                        <Image Width="64" Height="64" Margin="5">
                            <Image.Source>
                                <BitmapImage UriSource="{Binding Logo, TargetNullValue='ms-appx:///Assets/fallback.png', FallbackValue='ms-appx:///Assets/fallback.png'}"/>
                            </Image.Source>
                        </Image>
                        <StackPanel Orientation="Vertical" Margin="5">
                            <TextBlock Text="{Binding DisplayName, TargetNullValue='Unknown', FallbackValue='Unknown'}" FontWeight="Bold" />
                            <TextBlock Text="{Binding PublisherDisplayName, TargetNullValue='Unknown', FallbackValue='Unknown'}" />
                        </StackPanel>
                    </StackPanel>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</ContentDialog>

C#代码

using Microsoft.UI.Xaml.Controls;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using Windows.ApplicationModel;
using Windows.Management.Deployment;

namespace Program
{
    public sealed partial class AllAppsList : ContentDialog
    {
        public List<Package> Packages { get; set; } = new List<Package>();

        public AllAppsList()
        {
            Packages = GetAllInstalledPackages();
            this.DataContext = this;
            this.InitializeComponent();
        }

        public static List<Package> GetAllInstalledPackages()
        {
            var pm = new PackageManager();
            return pm.FindPackagesForUser(WindowsIdentity.GetCurrent().User?.Value).ToList();
        }

        private void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
        {
        }

        private void ContentDialog_SecondaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
        {
        }
    }
}

修复方案

1. 异步加载应用图标,避免UI线程阻塞

直接绑定Package.Logo会导致UI线程在滚动时频繁阻塞,引发崩溃。可以通过转换器实现异步加载:

using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Media.Imaging;
using System.Threading.Tasks;
using Windows.ApplicationModel;

public class PackageLogoConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        var bitmap = new BitmapImage();
        if (value is Package package)
        {
            _ = LoadLogoAsync(bitmap, package);
            return bitmap;
        }
        bitmap.UriSource = new Uri("ms-appx:///Assets/fallback.png");
        return bitmap;
    }

    private async Task LoadLogoAsync(BitmapImage bitmap, Package package)
    {
        try
        {
            if (package.Logo != null)
            {
                await bitmap.SetSourceAsync(await package.Logo.OpenReadAsync());
            }
            else
            {
                bitmap.UriSource = new Uri("ms-appx:///Assets/fallback.png");
            }
        }
        catch
        {
            bitmap.UriSource = new Uri("ms-appx:///Assets/fallback.png");
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

在XAML中引用转换器并修改Image绑定:

<ContentDialog.Resources>
    <local:PackageLogoConverter x:Key="PackageLogoConverter"/>
</ContentDialog.Resources>

<!-- 修改后的Image控件 -->
<Image Width="64" Height="64" Margin="5"
       Source="{Binding Converter={StaticResource PackageLogoConverter}, FallbackValue='ms-appx:///Assets/fallback.png'}"/>

2. 封装Package数据,避免直接绑定系统对象

ListView虚拟化会频繁复用Item容器,直接绑定系统级的Package对象容易引发资源访问异常。可以将需要的属性封装到独立的ViewModel中:

public class AppPackageViewModel
{
    public string DisplayName { get; set; }
    public string PublisherDisplayName { get; set; }
    public Package Package { get; set; }

    public static AppPackageViewModel FromPackage(Package package)
    {
        return new AppPackageViewModel
        {
            DisplayName = package.DisplayName ?? "Unknown",
            PublisherDisplayName = package.PublisherDisplayName ?? "Unknown",
            Package = package
        };
    }
}

修改数据加载逻辑:

public List<AppPackageViewModel> Packages { get; set; } = new List<AppPackageViewModel>();

public AllAppsList()
{
    this.DataContext = this;
    this.InitializeComponent();
    _ = LoadPackagesAsync();
}

private async Task LoadPackagesAsync()
{
    Packages = await Task.Run(() => 
        GetAllInstalledPackages().Select(AppPackageViewModel.FromPackage).ToList()
    );
}

3. 异步加载数据,避免阻塞UI线程

将同步加载数据改为异步执行,避免构造函数阻塞UI导致滚动时异常:

private async Task LoadPackagesAsync()
{
    // 可在此添加加载指示器
    Packages = await Task.Run(() => 
        GetAllInstalledPackages().Select(AppPackageViewModel.FromPackage).ToList()
    );
    // 若使用ObservableCollection,无需手动更新;若用List,可调用绑定更新方法
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 20:05:06