wpfcollectionswpf-controlschildren

What's the easiest way to get the next sibling (wrapping) on a canvas in WPF?


We have a canvas that has a Children collection with an indexer. We have a reference to one of the children. We just want to get the next child in the list, and if we go past the end, we want to wrap around again.

We're currently doing this via looping to get the index of the one we have, then we increment that, check the bounds and wrap if necessary, then use that result to get the child from the indexer...

...but that just feels so three-lefts-to-go-right to me. I have to be missing something.

Note: If there's a generic solution for any index-based collection, that would be great, but even if it's just canvas-specific, that's fine too.


Solution

  • I could be missing something, but I think what you want could be easily achieved, say I have some XAML like this

    <Canvas x:Name="canv">
        <Rectangle x:Name="canvChild1"/>
        <Rectangle x:Name="canvChild2"/>
        <Rectangle x:Name="canvChild3"/>
        <Rectangle x:Name="canvChild4"/>
    </Canvas>
    

    Then all you need is to grab a safe index (ie one that wraps), so assuming I have a handle to the 1st element, and want to grab next, and then 4th and wants to grab next, I could use code like this

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
    
            Debug.WriteLine(GetSafeElementForIndex(
                this.canv.Children.IndexOf(canvChild1)).Name);
    
            Debug.WriteLine(GetSafeElementForIndex(
                this.canv.Children.IndexOf(canvChild4)).Name);
        }
    
    
        private FrameworkElement GetSafeElementForIndex(int currentIndex)
        {
            return (FrameworkElement)this.canv.Children[WrappedIndex(++currentIndex)];
        }
    
    
        private int WrappedIndex(int currentIndex)
        {
            return currentIndex % this.canv.Children.Count;
        }
    }
    

    This prints this:

    canvChild2

    canvChild1

    I think you could also use Colin Eberhardts excellent LINQ to Tree stuff, which would allow you to use LINQ against the Visual Tree : http://www.codeproject.com/Articles/62397/LINQ-to-Tree-A-Generic-Technique-for-Querying-Tree

    That is pretty handy stuff, that allows you to treat the VisualTree as you would XML, and navigate different axis.