{"record":{"id":"08ecae885a2515fe","repo":"tui-cs/Terminal.Gui","slug":"selecteditem-must-be-greater-than-0-or-less-than-t","errorCode":null,"errorMessage":"SelectedItem must be greater than 0 or less than the number of items.","messagePattern":"SelectedItem must be greater than 0 or less than the number of items\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"Terminal.Gui/Views/ListView/ListView.Selection.cs","lineNumber":355,"sourceCode":"    public event EventHandler<ValueChangedEventArgs<object?>>? ValueChangedUntyped;\n\n    #endregion\n\n    /// <summary>This is a convenience property that is an alias for <see cref=\"Value\"/>. Get or set the index of the currently selected item.</summary>\n    /// <value>The index of selected item or <see langword=\"null\"/> if no item is selected.</value>\n    public int? SelectedItem\n    {\n        get;\n        set\n        {\n            if (Source is null)\n            {\n                return;\n            }\n\n            if (value.HasValue && (value < 0 || value >= Source.Count))\n            {\n                throw new ArgumentException (@\"SelectedItem must be greater than 0 or less than the number of items.\");\n            }\n\n            int? oldValue = field;\n\n            if (oldValue == value)\n            {\n                return;\n            }\n\n            ValueChangingEventArgs<int?> changingArgs = new (oldValue, value);\n\n            if (OnValueChanging (changingArgs) || changingArgs.Handled)\n            {\n                return;\n            }\n\n            ValueChanging?.Invoke (this, changingArgs);\n","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/tui-cs/Terminal.Gui/blob/2e47b11478db083499917f2ad27c34d30efb0df1/Terminal.Gui/Views/ListView/ListView.Selection.cs#L337-L373","documentation":"Thrown by ListView.SelectedItem setter when value is non-null and is < 0 or >= Source.Count. ListView uses the index into the bound Source for selection, so an out-of-range index has no row to point at. The setter early-returns if Source is null (no items), so the throw only happens when there IS a source but the index falls outside it.","triggerScenarios":"Setting SelectedItem from a previously captured index after the underlying list shrank (items removed/filtered); computing the index from a search that returned -1; off-by-one using Count instead of Count-1; setting before the Source is assigned in one path but after in another.","commonSituations":"Filtering/search that reduces Source.Count without resetting the selection; navigation 'select last' using list.Count (not Count-1); binding to an ObservableCollection that mutated underneath.","solutions":["Clamp or null the index against the current Source.Count before assigning: listView.SelectedItem = Source.Count > 0 ? Math.Clamp(idx, 0, Source.Count - 1) : null;","When filtering, reset SelectedItem to null (or 0) before swapping the Source.","Use Source.Count - 1 for 'select last', not Source.Count."],"exampleFix":"// before\nlistView.SelectedItem = lastIndex; // lastIndex now stale after filter\n\n// after\nlistView.SelectedItem = listView.Source is { Count: > 0 } src\n    ? Math.Clamp(lastIndex, 0, src.Count - 1)\n    : null;","handlingStrategy":"validation","validationCode":"if (listView.Source is { Count: > 0 } src)\n{\n    listView.SelectedItem = Math.Clamp(idx, 0, src.Count - 1);\n}\nelse\n{\n    listView.SelectedItem = null;\n}","typeGuard":"static bool IsValidSelection(int? i, int count) => !i.HasValue || (i >= 0 && i < count);","tryCatchPattern":null,"preventionTips":["Reset SelectedItem when filtering changes Source.Count.","Use Source.Count - 1 for 'select last', never Source.Count.","Clamp externally-supplied indices against the live Source."],"tags":["listview","index","validation","precondition"],"backgroundTag":null,"analyzedSha":"2e47b11478db083499917f2ad27c34d30efb0df1","analyzedAt":"2026-08-13T19:20:08.826Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}