{"record":{"id":"08cf5c8a305dab46","repo":"dotnet/maui","slug":"itemtemplate-count-has-exceeded-the-limit-of-view-08cf5c","errorCode":null,"errorMessage":"ItemTemplate count has exceeded the limit of {ViewTypeCount}{Environment.NewLine}Please make sure to reuse DataTemplate objects","messagePattern":"ItemTemplate count has exceeded the limit of (.+?)(.+?)Please make sure to reuse DataTemplate objects","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/Compatibility/Core/src/Android/Renderers/ListViewAdapter.cs","lineNumber":198,"sourceCode":"\t\t\t\t}\n\n\t\t\t\titemTemplate = selector.SelectTemplate(item, _listView);\n\t\t\t}\n\n\t\t\t// check again to guard against DataTemplateSelectors that return null\n\t\t\tif (itemTemplate == null)\n\t\t\t\treturn DefaultItemTemplateId;\n\n\t\t\tif (!_templateToId.TryGetValue(itemTemplate, out int key))\n\t\t\t{\n\t\t\t\t_dataTemplateIncrementer++;\n\t\t\t\tkey = _dataTemplateIncrementer;\n\t\t\t\t_templateToId[itemTemplate] = key;\n\t\t\t}\n\n\t\t\tif (key >= ViewTypeCount)\n\t\t\t{\n\t\t\t\tthrow new Exception($\"ItemTemplate count has exceeded the limit of {ViewTypeCount}\" + Environment.NewLine +\n\t\t\t\t\t\t\t\t\t \"Please make sure to reuse DataTemplate objects\");\n\t\t\t}\n\n\t\t\treturn key;\n\t\t}\n\n\t\tpublic override AView GetView(int position, AView convertView, ViewGroup parent)\n\t\t{\n\t\t\tCell cell = null;\n\n\t\t\tPerformance.Start(out string reference);\n\n\t\t\tListViewCachingStrategy cachingStrategy = Controller.CachingStrategy;\n\t\t\tvar nextCellIsHeader = false;\n\t\t\tif (cachingStrategy == ListViewCachingStrategy.RetainElement || convertView == null)\n\t\t\t{\n\t\t\t\tif (_listView.IsGroupingEnabled)\n\t\t\t\t{","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/dotnet/maui/blob/f377ff1c5ee04d334d8a925f50c83a6b7afddf03/src/Compatibility/Core/src/Android/Renderers/ListViewAdapter.cs#L180-L216","documentation":"ListViewAdapter.GetViewTypeForItemPath assigns each distinct DataTemplate a monotonically increasing integer key (stored in _templateToId, via _dataTemplateIncrementer) and throws if the key reaches ViewTypeCount. ViewTypeCount is Android's adapter view-type budget; exceeding it means the app is creating a new DataTemplate instance per item instead of reusing one.","triggerScenarios":"The app supplies a per-item DataTemplate factory that returns a NEW DataTemplate instance each call (e.g. inside a DataTemplateSelector returning `new DataTemplate(...)` per invocation), so _dataTemplateIncrementer climbs past ViewTypeCount.","commonSituations":"A DataTemplateSelector whose OnSelectTemplate returns `new DataTemplate(...)` rather than caching instances; building templates inside a loop or binding; using a lambda-based DataTemplate created per item.","solutions":["Cache DataTemplate instances — create them once (static fields, constructor) and return the same instance from the selector.","Make DataTemplateSelector.OnSelectTemplate idempotent per type: store templates as fields and reuse them.","Audit any code path that returns `new DataTemplate(...)` on the hot path and hoist it out."],"exampleFix":"// before\nprotected override DataTemplate OnSelectTemplate(object item, BindableObject container)\n{\n    return item is Header ? new DataTemplate(typeof(HeaderViewCell)) : new DataTemplate(typeof(RowViewCell));\n}\n// after — reuse instances\nprivate readonly DataTemplate _header = new DataTemplate(typeof(HeaderViewCell));\nprivate readonly DataTemplate _row = new DataTemplate(typeof(RowViewCell));\nprotected override DataTemplate OnSelectTemplate(object item, BindableObject container)\n    => item is Header ? _header : _row;","handlingStrategy":"validation","validationCode":"class SafeTemplateSelector : DataTemplateSelector\n{\n    readonly Dictionary<Type, DataTemplate> _cache = new();\n    DataTemplate GetOrCreate<TCell>() where TCell : Cell\n        => _cache.GetOrAdd(typeof(TCell), _ => new DataTemplate(typeof(TCell)));\n    protected override DataTemplate OnSelectTemplate(object item, BindableObject container)\n        => item is Header ? GetOrCreate<HeaderCell>() : GetOrCreate<RowCell>();\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never return `new DataTemplate(...)` per item from a selector — cache instances.","Store templates as static/instance fields initialized once.","Unit-test the selector to assert reference-equality reuse across calls.","Monitor _templateToId growth in integration tests for large lists."],"tags":["android","listview","datatemplate","memory","adapter","perf","maui-compat"],"backgroundTag":null,"analyzedSha":"f377ff1c5ee04d334d8a925f50c83a6b7afddf03","analyzedAt":"2026-08-13T14:26:18.069Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}