{"record":{"id":"538903636632fa50","repo":"stride3d/stride","slug":"unable-to-find-a-parent-selector-to-the-associated","errorCode":null,"errorMessage":"Unable to find a parent Selector to the associated VirtualizingTilePanel.","messagePattern":"Unable to find a parent Selector to the associated VirtualizingTilePanel\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/presentation/Stride.Core.Presentation.Wpf/Behaviors/TilePanelNavigationBehavior.cs","lineNumber":30,"sourceCode":"namespace Stride.Core.Presentation.Behaviors\n{\n    public class TilePanelNavigationBehavior : DeferredBehaviorBase<VirtualizingTilePanel>\n    {\n        private Selector selector;\n\n        protected override void OnAttachedAndLoaded()\n        {\n            DependencyObject parent = AssociatedObject;\n            while (parent != null)\n            {\n                parent = VisualTreeHelper.GetParent(parent);\n                if (parent is Selector)\n                    break;\n            }\n\n            if (parent == null)\n            {\n                throw new InvalidOperationException(\"Unable to find a parent Selector to the associated VirtualizingTilePanel.\");\n            }\n\n            selector = (Selector)parent;\n\n            selector.IsSynchronizedWithCurrentItem = true;\n            KeyboardNavigation.SetDirectionalNavigation(selector, KeyboardNavigationMode.None);\n\n            selector.PreviewKeyDown += OnAssociatedObjectKeyDown;\n        }\n\n        protected override void OnDetachingAndUnloaded()\n        {\n            if (selector != null)\n                selector.PreviewKeyDown -= OnAssociatedObjectKeyDown;\n            selector = null;\n        }\n\n        private void OnAssociatedObjectKeyDown(object sender, [NotNull] KeyEventArgs e)","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/presentation/Stride.Core.Presentation.Wpf/Behaviors/TilePanelNavigationBehavior.cs#L12-L48","documentation":"TilePanelNavigationBehavior maps keyboard arrow-key navigation onto a Selector that hosts a VirtualizingTilePanel. In OnAttachedAndLoaded it walks the visual tree upward from the panel to find an ancestor of type Selector; if the walk reaches null without finding one, it throws InvalidOperationException since the behavior has no selector to synchronize and configure.","triggerScenarios":"Attaching TilePanelNavigationBehavior to a VirtualizingTilePanel that is NOT placed inside a ListBox/ListView/ComboBox/other Selector — e.g. used directly inside a Grid, ItemsControl, or ContentControl; detaching/re-parenting the panel so its ancestor chain is broken at load time.","commonSituations":"Using VirtualizingTilePanel standalone for layout and adding the navigation behavior anyway; wrapping the panel in an ItemsControl instead of a ListBox because no selection is wanted; template restructuring that moved the panel outside the Selector subtree before the behavior runs.","solutions":["Place the VirtualizingTilePanel inside a Selector-derived control, e.g. <ListBox ItemsPanel> containing the panel as ItemsPanel.","If selection is not desired, set the ListBox to disable selection visually rather than switching to ItemsControl, or remove this behavior.","Ensure the behavior attaches after the panel is in the visual tree under the selector (check OnAttachedAndLoaded conditions and re-parenting timing)."],"exampleFix":"<!-- before: panel not inside a Selector -->\n<ItemsControl ItemsSource=\"{Binding Items}\">\n  <ItemsControl.ItemsPanel>\n    <ItemsPanelTemplate>\n      <wpf:VirtualizingTilePanel>\n        <i:Interaction.Behaviors>\n          <b:TilePanelNavigationBehavior />\n        </i:Interaction.Behaviors>\n      </wpf:VirtualizingTilePanel>\n    </ItemsPanelTemplate>\n  </ItemsControl.ItemsPanel>\n</ItemsControl>\n\n<!-- after -->\n<ListBox ItemsSource=\"{Binding Items}\">\n  <ListBox.ItemsPanel>\n    <ItemsPanelTemplate>\n      <wpf:VirtualizingTilePanel>\n        <i:Interaction.Behaviors>\n          <b:TilePanelNavigationBehavior />\n        </i:Interaction.Behaviors>\n      </wpf:VirtualizingTilePanel>\n    </ItemsPanelTemplate>\n  </ListBox.ItemsPanel>\n</ListBox>","handlingStrategy":"validation","validationCode":"DependencyObject WalkUpForSelector(DependencyObject start)\n{\n    var parent = LogicalTreeHelper.GetParent(start) ?? VisualTreeHelper.GetParent(start);\n    while (parent != null && !(parent is System.Windows.Controls.Primitives.Selector))\n        parent = LogicalTreeHelper.GetParent(parent) ?? VisualTreeHelper.GetParent(parent);\n    return parent;\n}\n// before attach: if (WalkUpForSelector(tilePanel) == null) log.Warn(\"TilePanelNavigationBehavior requires a Selector ancestor\");","typeGuard":"static bool HasSelectorAncestor(DependencyObject o) => WalkUpForSelector(o) is System.Windows.Controls.Primitives.Selector;","tryCatchPattern":"try { AttachBehavior(behavior, tilePanel); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"parent Selector\")) { log.Error(\"Place VirtualizingTilePanel inside a ListBox/ListView or another Selector\"); }","preventionTips":["Always host VirtualizingTilePanel as the ItemsPanel of a Selector-derived control when using this behavior.","Avoid ItemsControl for this panel if keyboard navigation via the behavior is required.","Re-check ancestor chain after any template re-parenting that moves the panel."],"tags":["wpf","panel","selector","navigation"],"backgroundTag":"resource-not-found","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}