views:

693

answers:

3

I have a stackpanel with some usercontrols that are added or removed during runtime. These elements have an index that i assign to them when i new them, I need to keep these elements sorted by that index so i wote a quicksort function that sorts them based on the index but on the line that does the swapping

          y = items[i]; //y is a temp variable
          items[i] = items[j];

I get

"Specified index is already in use. Disconnect the Visual child at the specified index first"

I tried copying them to a temp variable, delete them from the collection and then assign them to their right index with the Insert function in the UIElementCollection, but then I Get

"Specified Visual is already a child of another Visual or the root of a CompositionTarget"

Is there a clone element that i need or something im missing somewhere?

+4  A: 

Why dont you use a ListBox/ItemsSontrol and use CollectionViewSorce/SortDescription on it to get this work done. Adding an elements to the LayOut Panels like stackpanel is not an efficient way to go in WPF apps. StackPanel with vertical orientation is the default for ListBox/ItemsControl,but if you want some different layout you can always override ListBox.ItemsPanel Template

If you can follow MVVM apporach then it is a matter of specifying a property(in your case it willbe Index) in your ViewModel class and set SortDescription at the listBox level will automatically give you this feature. Instead of adding and removing actual UIElements, you need just to add/remove to the ObservableCollection bind to ListBox.ItemsSource. And specify proper DataTemplate.

Check this if you arent familiar with CollectionViewSource - http://msdn.microsoft.com/en-us/library/system.windows.data.collectionviewsource.sortdescriptions.aspx

And the code will be more like below.. it is pretty simple.

   <UserControl.Resources>
    <CollectionViewSource x:Key="sourceCollection" Source="{Binding YourObservableCollectionProperty}">
       <CollectionViewSource.SortDescriptions>
        <scm:SortDescription PropertyName="YourProperty-Index"/>
       </CollectionViewSource.SortDescriptions>
     </CollectionViewSource>
   </UserControl.Resources>       

  <ItemsControl ItemsSource="{Binding Source={StaticResource sourceCollection}}"/>

note:<--xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"-->

Jobi Joy
well I could...but that still yields the same results when i try to swap two element's positions. I pretty much use any container...but i want to be able to reorder them, or have away to sort them by the index that i specify
irco
First: use an ItemsControl, not a ListBox: the former is for lists of things that aren't inherently selectable.@irco: Manually repositioning elements like this from outside of a control isn't easily supported in the way you're trying to do it, but if you can reorder the source data (instead of the controls) then you'll achieve the same result.Jobi's suggestion is correct: a CollectionView will sort your list automatically according to the index you've specified (even if your list is a list of controls!).
Dan Puzey
I do that, the data to create the elements come from a db, they are sorted..the problem is that new elements can show up on the table at anytime and i cant just wipe out the container's collection, so when i add a new element with an index smaller than the last element and its added to the end, the need for sorting comes up. I will try the ItemsControl
irco
@JobiJoy I guess I'm not familiar enough with wpf yet, is my first project using it. I'm not sure as to what the StaticResource needs to be, as the data to create the userControls comes froma DB. if you can point me out in the right direction, I'd appreciate it
irco
Please read this article to get an idea of View Model way of WPF development. http://msdn.microsoft.com/en-us/magazine/dd419663.aspxHow are you accessing DB? LINQ2SQL? You need to look in to the ideas of ObservableCollection,DataTemplate and ItemsControl in WPF
Jobi Joy
thanks, I'll start reading that...the database is being accessed the old way...with code, with a sqlDataReader,based on the rows in a table the usercontrols are added and updated dynamically
irco
A: 

if you give each element specific name (which is index). when you remove this control, you can just rename the result controls.

after that all your control will be sorted.

Hashim Al-Arab
no there is a lot more information that just the index, I would need to transfer all the information down or up if i did that
irco
A: 

If you want to do that you need to make sure that the Parent is null and also that your index into your panel is not in use.

If you just swap it into a temp variable, it's still the same reference.

Use the Visual Tree Helper in order to disconnter or move your UIElement.

NPayette
I'm not sure I quite get what you mean....the parent is the StackPanel.Children collection, if it is null I'll lose the rest of the elements in there, and the index might be used but thats the idea of sorting..putting elements where other are..also the stackPanel.Children.Insert should push the elements down
irco