I have an ObservableCollection which is bound to some ItemsControl (FlipView) as its ItemsSource. I was having an issue with the scrolling on a touch device where the entire FlipView would disappear as soon as user touches the screen and it would reappear when the finger is removed from the screen. So to fix that, I had to work around it by clearing the collection whenever I had to refresh it (instead of re-instantiating it). I noticed that the same issue (with touch) was occurring when I used .Clear() in order to clear the collection but when I looped through the collection and removed the items one-by-one the issue was resolved.
So, I am still not clear as to what is the difference b/w these two ways of clearing the ObservableCollection?
If I remember correctly internally the ObservableCollection maintains a IList which is assigned an instance of List. The ObservableCollection.Clear method eventually calls Clear on the interal list and that List.Clear method then uses Array.Clear to clear the items.
Related
I need to change Visibility of all items in listbox in code based on changing some filters. I tried to loop the items using
myListbox.ContainerFromIndex(i)
but only first a few didn't return null. The answer why I quickly found here:
Why ItemContainerGenerator.ContainerFromIndex() returns null and how to avoid this behavior?
Turning off virtualization doesn't look like respectable solution to me, also I don't feel well about scrolling every item to view before calling ContainerFromIndex, even if it could probably work.
I'm not very clever from the rest of topics dealing with bindings and dependency properties etc, maybe also because majority of them are written in xaml and not in code. But I'm pretty sure the answer should be there. I'm very new to c# and I didn't find any clear-cut solution to such a basic problem.
I will prepare something like this array of Visibilities
Visibility[] visibilities=new Visibility[100]
...
and I want myListBox with 100 items to use these values. Either automatically with some c# magic or in a cycle as I used to do in Win32.
Based on the comment of Depechie, I made a research targeted on collections and created a functional code. Here is what I did:
Instead of adding items directly to listbox by
lbGames.Items.Add(...)
I created two collections:
List<object> gameList=new List<object>();
ObservableCollection<object> filteredGameList = new ObservableCollection<object>();
Adding items this way:
gameList.Add(...); or filteredGameList.Add(...)
While gameList is holding all items (stack panels), filteredGameList is holding only those I want visible. I had some problems with using only one big collection using its Visibility property, maybe my mistake, maybe not.
Withouth ObservableCollection I wasn't able to redraw listbox, that was problem with another List<> holding filtered data. When I filter data, I first clear filteredGameList and then I add all items I want visible, never changing Visibility property. ObservableCollection always tells listbox when items change.
On the application init, I attach listbox to this filteredGamesList.
lbGames.ItemsSource = filteredGameList;
Now everything works fine.
So I'm getting a weird behavior with the native LongListSelector from WP8.
It's ItemSource is bound to an
ObservableCollection<Group<Something>>
Everything is displayed correctly, but when the list appears on screen, I'm at the bottom of the list instead of it's top.
The only thing I do is to fill the ObservableCollection via it's Add() Method.
Is this a known behavior or is there a workaround ?
It is a normal behaviour as you are adding items one-by-one. for required behaviour kindly feed the list and then set it to observable collection
I have my own DefferedList:IList class. I overrode
Count, IndexOf, this[]
members and put
Debug.WriteLine("Get " + index);
into this[int index].
Then I binded instance of this class to ListBox.ItemSource.
Everything is fine but UI virtualization works a bit strange for me. I run application. ListBox is populated by first 17 items (from 0 to 17). Then I jump to 200th item
TheList.ScrollIntoView(Item200);
ListBox requests 200th item, then again items from 0 to 16 and finally 184-209.
So why does it request again 0-16 items while they are not visible anymore? It affects performance of my data virtualization very badly.
How to avoid it?
I have some really bad experience with numerous hours wasted in productivity over using custom virtualization of lists used in a standard ListBox. I would advise against using custom lists and use an ObservableCollection instead. I think ListBox was probably mostly tested with an ObservableCollection and any tricks you try to make to avoid populating the entire list are likely to backfire since the ListBox is not really as flexible as you would expect based on the fact that ItemsSource is just an IEnumerable. Actually based on that expectation - you could assume that it needs to enumerate all items between 0 and 200 if you want to display item 200.
If you have a few hundred items in a list - you might want to simplify the data model for displaying them, so you populate an ObservableCollection with all the items from the beginning and only load the item data when the contents of the items are requested and not already available. If that is too much - you could add a small delay before loading the data and check if the collection item view is visible on screen after that delay before you start loading.
Another thing that is supposedly helpful is if your ItemTemplate is of predefined dimensions.
I have a ListBox that is bound to a List. Every-time the ListBox updates to reflect the collection, the SelectedIndex changes to the top item. How can stop this behavior and retain the current SelectedIndex?
[UPDATE]
I found a better collection to use for this kind of functionality - the 'BindingList': http://msdn.microsoft.com/en-us/library/ms132679(v=VS.90).aspx.
WulfgarPro.
When [...] updates to reflect the collection
Does that mean there is a new collection? If so what does "the same position" mean?
When re-binding to a(nother) list, you will have to save & restore the index position. Just write code around the place where you update the DataSource.
Using the BindingList collection rather than a List remedied a lot of my problems. I was originally using a Thread and a Delegate to query the collection and call ListBox.DataSource=[..] to update the binding. This was slow, cumbersome and error prone. Not to mention my original problem of not being able to easily retain the SelectedItem. Changing to to the BindingList allowed me to remove the thread and delegate and now everything works as intended. Assigning the desired display property for the ListBox can be achieved using ListBox.DisplayMember=[..].
WulfgarPro.
I have WPF listview bound to collection of objects. Objects are continuously added in to collection from remote server and same is reflecting in to listview. Now we have requirement that we should be able to freeze listview for some time,
That is objects should still get added in to collection but should not appear in listview till we unfreeze it ( we have button to freeze and unfreeze) . What is the best way to do it, when listview is bound to collection ? How to unbind collection and rebind it ? and Will i still able to filter and sort when collection is unbound from listview ? Waiting for answer please reply
Regards
Sandeep
You can just break the binding. In your freeze button handler say:
listView = _list
Which will freeze it at that point. Then in your unfreeze handler set the binding back up:
listView.SetBinding(ListView.ItemsSourceProperty, New Binding("_list"))
I hope this helps.
You should just stop updating the collection when the list is frozen, if you must keep adding to the collection even when the list is frozen (if the same collection is used somewhere else that shouldn't be frozen) then consider having two collections, one always updated and the other one bound to the listview.
What is the list type you are using as the data-source? Can you use BindingList<T>? If so, this has a settable RaiseListChangedEvents property, allowing you to turn off notifications. This will probably get very messy re your last points, though (sort/filter).
Personally, I'd work with 2 lists - the bound one, and the one that the server is updating. When paused, simply stop pumping data between the two. This should leave the paused view free for sorting / filtering etc.