dotnet/maui · error · Exception
ItemTemplate count has exceeded the limit of {ViewTypeCount}
Error message
ItemTemplate count has exceeded the limit of {ViewTypeCount}
Please make sure to reuse DataTemplate objects What it means
The ListViewAdapter assigns a unique integer key to each distinct DataTemplate instance it encounters via the _templateToId dictionary and _dataTemplateIncrementer (starting at 2). The ViewTypeCount property returns 23 (ListViewAdapter.cs:125), so the effective limit is approximately 21 unique DataTemplate instances (incrementer starts at 2, and keys must stay below 23). When a new DataTemplate instance pushes the key beyond ViewTypeCount, Android's adapter contract is violated and the exception is thrown. The most common cause is a DataTemplateSelector that creates new DataTemplate instances per call to OnSelectTemplate instead of caching and reusing them.
Source
Thrown at src/Compatibility/Core.LegacyRenderers/Android/ListViewAdapter.cs:197
}
itemTemplate = selector.SelectTemplate(item, _listView);
}
// check again to guard against DataTemplateSelectors that return null
if (itemTemplate == null)
return DefaultItemTemplateId;
if (!_templateToId.TryGetValue(itemTemplate, out int key))
{
_dataTemplateIncrementer++;
key = _dataTemplateIncrementer;
_templateToId[itemTemplate] = key;
}
if (key >= ViewTypeCount)
{
throw new Exception($"ItemTemplate count has exceeded the limit of {ViewTypeCount}" + Environment.NewLine +
"Please make sure to reuse DataTemplate objects");
}
return key;
}
public override AView GetView(int position, AView convertView, ViewGroup parent)
{
Cell cell = null;
Performance.Start(out string reference);
ListViewCachingStrategy cachingStrategy = Controller.CachingStrategy;
var nextCellIsHeader = false;
if (cachingStrategy == ListViewCachingStrategy.RetainElement || convertView == null)
{
if (_listView.IsGroupingEnabled)
{View on GitHub (pinned to f377ff1c5e)
Solutions
- Cache DataTemplate instances in the DataTemplateSelector as static or instance fields and return the cached references from OnSelectTemplate.
- If using a DataTemplateSelector, pre-create all templates once and reuse them: 'static readonly DataTemplate _templateA = new DataTemplate(typeof(ViewA));'
- Reduce the number of distinct templates to stay within the 20-template documented limit.
- If you truly need more view types, use a CollectionView with a custom handler or a third-party virtualized list that does not have the Android AdapterView ViewTypeCount constraint.
- Switch from ListView to CollectionView (Microsoft.Maui.Controls.CollectionView), which uses RecyclerView and has no hard ViewTypeCount limit.
Example fix
// before — creates new DataTemplate per call (causes the error)
public class MyTemplateSelector : DataTemplateSelector
{
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
var type = (item as MyModel)?.Type;
return type switch
{
"A" => new DataTemplate(() => new ViewA()),
"B" => new DataTemplate(() => new ViewB()),
_ => new DataTemplate(() => new ViewDefault())
};
}
}
// after — cached and reused (fixes the error)
public class MyTemplateSelector : DataTemplateSelector
{
readonly DataTemplate _a = new DataTemplate(() => new ViewA());
readonly DataTemplate _b = new DataTemplate(() => new ViewB());
readonly DataTemplate _default = new DataTemplate(() => new ViewDefault());
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
var type = (item as MyModel)?.Type;
return type switch
{
"A" => _a,
"B" => _b,
_ => _default
};
}
} Defensive patterns
Strategy: validation
Validate before calling
// Pre-validate: count unique DataTemplate instances your selector can return
var uniqueTemplates = new HashSet<DataTemplate>();
foreach (var item in sampleItems)
{
var template = selector.SelectTemplate(item, listView);
uniqueTemplates.Add(template);
}
if (uniqueTemplates.Count > 20)
{
throw new InvalidOperationException($"DataTemplateSelector returns {uniqueTemplates.Count} unique DataTemplate instances; limit is ~20. Cache and reuse templates.");
} Type guard
// Verify the DataTemplateSelector caches its templates (no per-call allocation)
static bool SelectorCachesTemplates(DataTemplateSelector selector)
{
// Call SelectTemplate twice with equivalent items and check reference equality
var dummy = new object();
var t1 = selector.SelectTemplate(dummy, null);
var t2 = selector.SelectTemplate(dummy, null);
return ReferenceEquals(t1, t2);
} Prevention
- Always cache DataTemplate instances as fields in DataTemplateSelector subclasses; never allocate new ones in OnSelectTemplate.
- Migrate from ListView to CollectionView to escape the Android AdapterView ViewTypeCount constraint entirely.
- Unit test DataTemplateSelector implementations to verify the number of unique DataTemplate references returned does not exceed 20.
- Static-analysis or code review: flag any 'new DataTemplate(' inside a method that runs per-item.
- If using lambda-based DataTemplate constructors, extract them to static fields.
When it happens
Trigger: GetItemViewType assigns a new incrementing key for each unique DataTemplate reference. If a DataTemplateSelector's SelectTemplate method returns 'new DataTemplate(() => new View())' each time it is called for different data items, every distinct return creates a new dictionary entry, and the counter eventually exceeds 23. The exception fires on the item that pushes it over.
Common situations: DataTemplateSelector returning new DataTemplate instances in OnSelectTemplate without caching; creating DataTemplate objects inside a data-binding converter or inside a cell factory that runs per-item; binding a ListView's ItemTemplate to a property that returns a new DataTemplate each getter call; using a lambda-based DataTemplate constructor inside a hot path; large heterogeneous lists where each item type gets a distinct template and there are more than ~20 types.
Related errors
- ItemTemplate count has exceeded the limit of {ViewTypeCount}
- ItemTemplate count has exceeded the limit of {ViewTypeCount}
- The Map.ItemTemplate property only supports DataTemplate. Se
- View for cell must implement INativeElementView to enable re
- ViewCell must have a View
AI-assisted analysis of dotnet/maui@f377ff1c5e (2026-08-13).
Data as JSON: /api/errors/360851da02e4b7a0.
Report an issue: GitHub.