.NET MAUI中ControlTemplate含CollectionView+ContentPresenter引发异常
问题:使用ControlTemplate实现列表视图时,导航返回抛出"No installed components were detected"异常
我们有多个展示Model列表的View,点击列表项会显示操作菜单,原本功能正常。为保证视图一致性,尝试用ControlTemplate重构。首次测试时ItemsSource仅含单个项,功能看似正常;但当ItemsSource包含多个项时,导航离开再返回视图会抛出No installed components were detected异常,不过首个项仍能正常渲染和响应点击。
涉及代码文件
ListViewsTemplate.xaml(控件模板)
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MauiIssues.Controls.ListViewsTemplate" ControlTemplate="{DynamicResource ContainerTemplate}" x:Name="this"> <ContentView.Resources> <ResourceDictionary> <ControlTemplate x:Key="ContainerTemplate"> <Frame BindingContext="{x:Reference this}" Padding="10, 0, 10, 0"> <CollectionView ItemsSource="{TemplateBinding ItemsSource}"> <CollectionView.ItemsLayout><LinearItemsLayout Orientation="Vertical" /></CollectionView.ItemsLayout> <CollectionView.ItemTemplate> <DataTemplate> <Grid> <Frame> <Frame.GestureRecognizers> <TapGestureRecognizer Command="{TemplateBinding ItemTapped}" CommandParameter="{Binding .}" /> </Frame.GestureRecognizers> <ContentPresenter /> </Frame> <Rectangle IsVisible="{OnPlatform false, Android=True}" HeightRequest="2" Fill="Black"/> </Grid> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </Frame> </ControlTemplate> </ResourceDictionary> </ContentView.Resources> </ContentView>
ListViewsTemplate.xaml.cs(控件模板代码后置)
using System.Collections; using System.Windows.Command; namespace MauiIssues.Controls { public partial class ListViewsTemplate : ContentView { public IEnumerable ItemsSource { get => (IEnumerable)GetValue(ItemsSourceProperty); set => SetValue(ItemsSourceProperty, value); } public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create(nameof(ItemsSource), typeof(IEnumerable), typeof(ListViewsTemplate), defaultBindingMode: BindingMode.TwoWay); public ICommand ItemTapped { get => (ICommand)GetValue(ItemTappedProperty); set => SetValue(ItemTappedProperty, value); } public static readonly BindableProperty ItemTappedProperty = BindableProperty.Create(nameof(ItemTapped), typeof(ICommand), typeof(ListViewsTemplate), defaultBindingMode: BindingMode.TwoWay); public ListViewsTemplate() { InitializeComponent(); } } }
ListViewsTemplate.xaml(内容页)
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:model="clr-namespace:MauiIssues.Models" xmlns:uc="clr-namespace:MauiIssues.Controls" xmlns:viewmodel="clr-namespace:MauiIssues.ViewModels" x:Class="MauiIssues.Views.ListViewsTemplate" x:DataType="viewmodel:ListViewsTemplateViewModel"> <uc:ListViewsTemplate ItemsSource="{Binding Items}" ItemTapped="{Binding ItemTappedCommand}" VerticalOptions="StartAndExpand" > <Label BindingContext="{Binding Source={RelativeSource AncestorType={x:Type model:ListViewsTemplateModel}}}" x:DataType="{x:Type model:ListViewsTemplateModel}" Text="{Binding Name}" /> </uc:ListViewsTemplate> </ContentPage>
ListViewsTemplate.xaml.cs(内容页代码后置)
using MauiIssues.ViewModels; namespace MauiIssues.Views { public partial class ListViewsTemplate : ContentPage { public ListViewsTemplateViewModel ViewModel { get; } public ListViewsTemplate() { base.BindingContext = this.ViewModel = new ListViewsTemplateViewModel(); InitializeComponent(); } protected override async void OnAppearing() { await this.ViewModel.OnAppearing(); base.OnAppearing(); } } }
ListViewsTemplateViewModel.cs(视图模型)
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using MauiIssues.Models; using System.Collections.ObjectModel; namespace MauiIssues.ViewModels { public partial class ListViewsTemplateViewModel : ObservableObject { public ObservableCollection<ListViewsTemplateModel> Items { get; } = new (); [RelayCommand] async Task ItemTapped(ListViewsTemplateModel item) { await App.Current.MainPage.DisplayAlert("tapped item", item.Name, "OK"); } public async Task OnAppearing() { this.Items.Add(new ListViewsTemplateModel() { Name = $"Item {this.Items.Count + 1}" }); await Task.CompletedTask; } } }
异常堆栈信息
首次导航到视图时一切正常,但导航离开并返回时抛出以下异常:
No installed components were detected. at System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(Int32 errorCode) at WinRT.DelegateExtensions.DynamicInvokeAbi(Delegate del, Object[] invoke_params) at ABI.System.Collections.Generic.IVectorMethods`1.Append(IObjectReference obj, T value) at ABI.System.Collections.Generic.IListMethods`1.Add(IObjectReference obj, T item) at Microsoft.UI.Xaml.Controls.UIElementCollection.Add(UIElement item) at Microsoft.Maui.Handlers.ContentViewHandler.UpdateContent(IContentViewHandler handler) at Microsoft.Maui.Handlers.ContentViewHandler.MapContent(IContentViewHandler handler, IContentView page) at Microsoft.Maui.Controls.Element.OnPropertyChanged(String propertyName) at Microsoft.Maui.Controls.BindableObject.SetValueActual(BindableProperty property, BindablePropertyContext context, Object value, Boolean currentlyApplying, SetValueFlags attributes, Boolean silent) at Microsoft.Maui.Controls.BindableObject.SetValueCore(BindableProperty property, Object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes) at Microsoft.Maui.Controls.BindingExpression.ApplyCore(Object sourceObject, BindableObject target, BindableProperty property, Boolean fromTarget) at Microsoft.Maui.Controls.BindingExpression.Apply(Object sourceObject, BindableObject target, BindableProperty property) at Microsoft.Maui.Controls.Binding.d__27.MoveNext() at System.Threading.Tasks.Task.<>c.b__128_0(Object state) at Microsoft.UI.Dispatching.DispatcherQueueSynchronizationContext.<>c__DisplayClass2_0.b__0() --- End of stack trace from previous location --- at WinRT.ExceptionHelpers.g__Throw|20_0(Int32 hr) at ABI.Windows.ApplicationModel.Core.IUnhandledErrorMethods.Propagate(IObjectReference _obj) at Windows.ApplicationModel.Core.UnhandledError.Propagate() at Microsoft.AppCenter.Utils.ApplicationLifecycleHelperWinUI.<.ctor>b__0_3(Object sender, UnhandledErrorDetectedEventArgs eventArgs) --- End of stack trace from previous location --- at Microsoft.AppCenter.Utils.ApplicationLifecycleHelperWinUI.<.ctor>b__0_3(Object sender, UnhandledErrorDetectedEventArgs eventArgs) at WinRT.EventSource__EventHandler`1.EventState.<GetEventInvoke>b__1_0(Object obj, T e) at ABI.System.EventHandler`1.Do_Abi_Invoke[TAbi](Void* thisPtr, IntPtr sender, TAbi args)
更新说明
为更清晰说明需求,我们想要实现类似ASP.NET母版页的功能:每个Web页面使用母版页,并在ContentPlaceHolder中放置自定义控件,我们理解这正是ContentPresenter的用途。
ASP.NET母版页示例(Page.Master)
<body> <div class="main"> <asp:ContentPlaceHolder ID="FilterContent" runat="server" /> <asp:Button ID="btnSearch" runat="server" Text="Search" /> <div class="filterseparator" /> <asp:ContentPlaceHolder ID="GridContent" runat="server" /> <div class="gridseparator" /> <asp:ContentPlaceHolder ID="MainContent" runat="server" /> </div> </body>
内容的提问来源于stack exchange,提问作者dpTech
相关产品推荐
相关产品推荐

