I have a ListView and ObservableCollection in my wpf application.
I want to bind linq expression to ListView:
lv_Results.DataContext = store.Where(x => x.PR > 5).ToList();
tempStore = new M1Store()
{
SiteName = siteName,
Date = date,
url = IndexedPage,
TCY = YandexTCY.GetYandexTCY(IndexedPage),
PR = Pagerank.GetPR(IndexedPage)
};
store.Add(tempStore);
But when i add new elements to store collection, lv_Results doesnt updates.
How can i update ListView?
Your problem is that you want the "Where" condition to be evaluated continuously on all items added to the "store" collection. The built-in LINQ "Where" operator is not designed to do that. Rather, when it is enumerated by the ListView it scans your collection exactly once then ignores it from then on.
Check out Continuous LINQ. It is designed to do exactly what you are looking for, and can be used almost as a drop-in replacement for standard LINQ queries.
Limitations of the built-in LINQ implementation
The built-in LINQ extension methods have a fundamental limitation in that the collections they produce don't support INotifyPropertyChanged. So no matter how much the underlying data changes, the client will never receive notification that the collection has changed and hence will never refresh its display of the data.
User jrista points out in the comments that the built-in LINQ methods do actually produce up-to-date data if re-enumerated. While true, this has no practical effect. No WinForms or WPF control contains code to periodically re-enumerate its data source. The reasons for not doing so are, of course, obvious: It would be incredibly wasteful. If you re-enumerate 10 times per second and it takes 10ms to re-enumerate and scan for changes you will use up 10% of your CPU for just one control!
Put your LINQ results into an ObservableCollection. WPF and Silverlight databinding require that collections raise change notifications, and ObservableCollection does that for you. Otherwise you'd have to implement it yourself, which is more of a pain and completely unnecessary.
The results from the LINQ expression are being fed into a new List(of T) which does not raise PropertyChanged or CollectionChanged events.
The easiest way to make it work is to retrieve the results you want, then populate an ObservableCollection(of T) with the results you want to display. As that ObservableCollection gets added to, the new items will appear in the ListView.
Add a .ToList() to your code, LINQ evaluates lazy, so it brings results only when needed, .ToList() is a greedy operator and forces an evaluation.
[edit]
Sorry, missunterstood your first version of the question :)
Here's my solution:
ObservableCollection<M1Store> l = store.Where(x => x.PR > 5);
lv_Results.DataContext = l;
Thats simply all, in all following steps, change the Observable collection l:
List<M1Store> otherList = GetFromAnywhere();
otherList.ForEach(e => l.Add(e));
Here the internals of the Observable Collection will Update the listView in the UI.
Related
I'm working on a WPF application that utilizes ReactiveUI and DynamicData. Most of our lists are of the type IObservableList and at times we need to subscribe to changes on this list, and at times we need to simply iterate through the list. My concern is around if we're following the correct pattern for iterating through these lists.
Currently, when we need to iterate through a list, we follow the following pattern:
// Assuming we have an IObservableList<SomeObject> named objList with some data in it
foreach (var obj in objList.Items)
{
// some operation on obj
}
This pattern works fine, but we're concerned that this isn't a "Reactive" way to do this. Any suggestions?
Thank you!
Well, I'm not quite familiarized with IObservableList<T>, but I use Deferred Execution when working with IList<T>.
I would recommend to implement this when working with dynamic data, it will let you get the latest values whenever you need them.
check the link for more details.
You iterate through a list using a loop. Each of them works.
for is the obvious first candidate.
while works, but is a bit more writing.
foreach works - if you do not start changing the list. A quirk of foreach is that it only works with enumerators under the hood, and enumerators become invalid if the collection is changed.
One particulay thing to consider however is the "ElementAdded" Notification on (re)building the list. Usually they classes lack AddRange functions.
Unless you tell us what you do with SomeClass Instances during itteration and how the class looks, we can not tell you if it is "reactive" programming. But for me it feels like it is just a Buzzword.
Let's say I have an IReactiveList<string> named Items from which I'd like to create some derived list DerivedItems (of type IReactiveList<string> or IReactiveDerivedList<string>) of distinct items only.
Items.CreateDerivedCollection(...) has all the bells and whistles I'd like to use, but it doesn't appear to have an option for filtering out duplicates.
I tried Items.Distinct().CreateDerivedCollection(...), but CreateDerivedCollection() no longer tracks changes when used with Distinct().
I tried Items.Changed.Throttle(...).Subscribe(_ => ResetImpl()) where ResetImpl clears DerivedItems and adds each item in Items one-by-one, but then I get exceptions stating that the enumeration cannot complete because the collection was modified. (This occurs primarily when I add dependencies on DerivedList.) I can add a lot of locks but this seems pretty messy.
Finally I tried manually triggering off Items.IsEmptyChanged.Where(b => b) and Items.ItemsAdded in an attempt to manually synchronize Items and DerivedItems, but here I run into a lot of timing issues where list clearing and item addition do not consistently happen in the right order.
I get the feeling I'm missing an easy solution to this problem. How do you do this?
I have a way of doing it, but it's not using IReactiveDerivedList:
var distinctElements = Items.Distinct().ToList();
Items.Changed.Subscribe(y =>
{
distinctElements = Items.Distinct().ToList();
});
I'm looking for instruction to sort my listView after adding items. I don't want to use "auto sorting" because its very, very slow. I have 5 columns but I want to sort only by first column. Anyone?
listView1.BeginUpdate();
while (csv.ReadNextRecord())
listView1.Items.Add(new ListViewItem(new[] { csv[0], csv[1], csv[2], csv[3], csv[4] }));
// sort here
listView1.EndUpdate();
// or here
The best thing to do here is store you're data in a generic list and sort it before showing on the ui. Controls don't typically work well with that amount of data and therefore you have the added advantage of controlling a vie of your original data.
The other thing you can do here is provide a custom sorter to the list.sort method. Typically however your unlikely to get huge savings over the framework. Consider are sorting and displaying a progress indicator while waiting instead, this is pretty typical for long running processes.
If you want to do custom during look at the following link about custom compares http://msdn.microsoft.com/en-us/library/234b841s(v=vs.110).aspx
I look for a way to observe a collection for changes, without using indices. I know when items are added and removed from the source collection, but the collection is not using indices (it's a custom kind of hashset with notification on add/remove). Items are being populated to the list in a undeterministic order and using indices wouldnt make much sense, so I'm trying to avoid it completely. But Im still going to bind this list to a view, so there will be some ordering of the items eventually. My goal is to have all the ordering in a collectionview.
The question is if there is a way to make a collectionview on a index-less source collection and still get the UI to respond to items being removed and added effectively without having to rebuild the list everytime. I'm not sure if I make any sense here. My goal is to get rid of indices but still benefit from collectionchanged-events and collectionview-ordering. Possible?
UPDATE
I've tried to implement a custom ICollectionView such as SetCollectionView(HashSet set) but it won't work for some reason. Not yet anyway.
Another option could perhaps be to implement a custom ReadOnlyObservableCollection-wrapper with some custom ordering on the GetEnumerator. I haven't tested it yet. I would have to sort the list according to the choosen ordering before extracting the index for the NotifyCollectionChanged-event but that should work.
You can use the ObservableHashSet class.
See the question here
How can I make an Observable Hashset in C#?
or go directly to the code here:
http://geoffcox.bellacode.com/2011/12/09/observablehashset/
You need to have an index somewhere, because all of the UI binding plumbing is index-based. You can layer an indexed list over your existing hashset, but it's going to be slow (I can't provide a formal proof, but my gut tells me it would be quite awful, something like O(n)). If you want a quick base collection that you can layer re-ordered UI lists on top of, you might want to look into a balanced sorted tree, rather than a hashset.
I have a listbox which has a couple of values and is already populated (from user input). Later in my program I want to take these values from the listbox and populate them to a List collection.
One of the approach is of course to iterate through the items of the listbox and populate the List collection one by one (in a loop) using Add method.
But is there a better more efficient way to do this in one shot meaning all the items of the listbox get copied over to a List collection.
I also looked at the AddRange method but that doesnt seem to help.
Any suggestions for this?
It's not necessarily more efficient (in terms of speed/memory), but you can save some typing via LINQ:
List<string> items = listBox.Items.Cast<object>()
.Select(item => item.ToString()).ToList();
If it must be a List<string>, I think you will have to enumerate the items and add them to a list (since you are concerned about the efficiency of LINQ). If you can use a string[], you could use the CopyTo method:
string[] destination = new string[listBox1.Items.Count];
listBox1.Items.CopyTo(destination, 0);
The ItemCollection class implements IList, you'll need to cast the items in the collection to String since it's not a generic collection, but you already have a "List collection" of the items.
If you really need a copy of the items in collection then no, there isn't going to be a more efficient way. There are plenty of ways to implement syntatic sugar so that the code is more concise, but ultimately they will all be iterating over the items and creating copies to be added to a new collection.
No there isn't a more efficient way.
If anything existed it would simply abstract away what you will be doing anyways via an extension method or other means and could have the possibility of making your code less readable.
The CopyTo method does exist via the ObjectCollection on the Items property which could then be LINQ'ed to a List<T>.
ListBox lb = new ListBox();
object[] items = new object[lb.Items.Count];
lb.Items.CopyTo(items, 0);
This seems to be a duplicate of: Most succinct way to convert ListBox.items to a generic list
If you're copying from the listbox, what is populating that list? It might be a better option to go about it that way, versus taking 200k items and moving it over. if you're taking all items in a listbox, populate the List at the same time.
On that note.. really? 200k items in a listbox?. That right there seems a little over the top in a real world application.
Foreach(...) loops are very expensive - even when compiled into IL: http://diditwith.net/2006/10/05/PerformanceOfForeachVsListForEach.aspx
If you are unable to work with LINQ (your using <= VS 2005), this is one of the easier methods of doing it.
string[] items = new string[listBox1.Items.Count];
listBox1.Items.CopyTo(items, 0);
List<string> list = new List<string>(items);
#Aaron McIver, your own method is a bit faster in my opinion. See this link for some performance testing I have done.