stride3d/stride · error · InvalidOperationException

Unable to find a parent Selector to the associated…

Error message

Unable to find a parent Selector to the associated VirtualizingTilePanel.

What it means

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.

Solutions

  1. Place the VirtualizingTilePanel inside a Selector-derived control, e.g. <ListBox ItemsPanel> containing the panel as ItemsPanel.
  2. If selection is not desired, set the ListBox to disable selection visually rather than switching to ItemsControl, or remove this behavior.
  3. Ensure the behavior attaches after the panel is in the visual tree under the selector (check OnAttachedAndLoaded conditions and re-parenting timing).

Example fix

<!-- before: panel not inside a Selector -->
<ItemsControl ItemsSource="{Binding Items}">
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <wpf:VirtualizingTilePanel>
        <i:Interaction.Behaviors>
          <b:TilePanelNavigationBehavior />
        </i:Interaction.Behaviors>
      </wpf:VirtualizingTilePanel>
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
</ItemsControl>

<!-- after -->
<ListBox ItemsSource="{Binding Items}">
  <ListBox.ItemsPanel>
    <ItemsPanelTemplate>
      <wpf:VirtualizingTilePanel>
        <i:Interaction.Behaviors>
          <b:TilePanelNavigationBehavior />
        </i:Interaction.Behaviors>
      </wpf:VirtualizingTilePanel>
    </ItemsPanelTemplate>
  </ListBox.ItemsPanel>
</ListBox>
Defensive patterns

Strategy: validation

Validate before calling

DependencyObject WalkUpForSelector(DependencyObject start)
{
    var parent = LogicalTreeHelper.GetParent(start) ?? VisualTreeHelper.GetParent(start);
    while (parent != null && !(parent is System.Windows.Controls.Primitives.Selector))
        parent = LogicalTreeHelper.GetParent(parent) ?? VisualTreeHelper.GetParent(parent);
    return parent;
}
// before attach: if (WalkUpForSelector(tilePanel) == null) log.Warn("TilePanelNavigationBehavior requires a Selector ancestor");

Type guard

static bool HasSelectorAncestor(DependencyObject o) => WalkUpForSelector(o) is System.Windows.Controls.Primitives.Selector;

Try / catch

try { AttachBehavior(behavior, tilePanel); }
catch (InvalidOperationException ex) when (ex.Message.Contains("parent Selector")) { log.Error("Place VirtualizingTilePanel inside a ListBox/ListView or another Selector"); }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/538903636632fa50. Report an issue: GitHub.

Appendix: source

Thrown at sources/presentation/Stride.Core.Presentation.Wpf/Behaviors/TilePanelNavigationBehavior.cs:30

namespace Stride.Core.Presentation.Behaviors
{
    public class TilePanelNavigationBehavior : DeferredBehaviorBase<VirtualizingTilePanel>
    {
        private Selector selector;

        protected override void OnAttachedAndLoaded()
        {
            DependencyObject parent = AssociatedObject;
            while (parent != null)
            {
                parent = VisualTreeHelper.GetParent(parent);
                if (parent is Selector)
                    break;
            }

            if (parent == null)
            {
                throw new InvalidOperationException("Unable to find a parent Selector to the associated VirtualizingTilePanel.");
            }

            selector = (Selector)parent;

            selector.IsSynchronizedWithCurrentItem = true;
            KeyboardNavigation.SetDirectionalNavigation(selector, KeyboardNavigationMode.None);

            selector.PreviewKeyDown += OnAssociatedObjectKeyDown;
        }

        protected override void OnDetachingAndUnloaded()
        {
            if (selector != null)
                selector.PreviewKeyDown -= OnAssociatedObjectKeyDown;
            selector = null;
        }

        private void OnAssociatedObjectKeyDown(object sender, [NotNull] KeyEventArgs e)

View on GitHub (pinned to 96fad776d2)