c# - Accessing the first item in a CollectionViewSource containing multithreaded ObservableCollections -
as part of attempt fix my other problem regarding odd disabling, tried updating bound observablecollection instead of replacing whole thing every few seconds. gives error since event can't modify it. so, created multithreaded 1 based on this link.
public class mtobservablecollection<t> : observablecollection<t> { public override event notifycollectionchangedeventhandler collectionchanged; protected override void oncollectionchanged(notifycollectionchangedeventargs e) { var eh = collectionchanged; if (eh != null) { dispatcher dispatcher = (from notifycollectionchangedeventhandler nh in eh.getinvocationlist() let dpo = nh.target dispatcherobject dpo != null select dpo.dispatcher).firstordefault(); if (dispatcher != null && dispatcher.checkaccess() == false) { dispatcher.invoke(dispatcherpriority.databind, (action)(() => oncollectionchanged(e))); } else { foreach (notifycollectionchangedeventhandler nh in eh.getinvocationlist()) nh.invoke(this, e); } } } }
i changed references original collection use new one. changed event handler code add or update existing items in collections. works fine. view display updates correctly. since i'm updating instead of replacing, have use collectionviewsource
apply 2 different sort properties lists.
<collectionviewsource x:key="askdepthcollection" source="{binding path=askdepthasync}"> <collectionviewsource.sortdescriptions> <scm:sortdescription propertyname="sortorderkey" direction="ascending" /> <scm:sortdescription propertyname="quotepricedouble" direction="ascending" /> </collectionviewsource.sortdescriptions> </collectionviewsource> <collectionviewsource x:key="biddepthcollection" source="{binding path=biddepthasync}"> <collectionviewsource.sortdescriptions> <scm:sortdescription propertyname="sortorderkey" direction="ascending" /> <scm:sortdescription propertyname="quotepricedouble" direction="descending" /> </collectionviewsource.sortdescriptions> </collectionviewsource>
of course means view sorted , not collection itself. need data of viewmodel ends in first position. big buttons (shown on other issue) have reflect data first position. tab manager has of business code has access host form , main viewmodel. not work directly tab control hosting list. so, these things i've tried.
- create
firstinview
extension based on this post. tried using within parent viewmodel, within tab manager, calling mycollectionproperty.firstinview(). - tried access using examples this post.
- attempted use movecurrenttofirst mentioned in post.
- looked @ this code review, decided wouldn't since items can added, removed, or updated cause them move anywhere in view every few seconds.
all of attempts retrieve first viewmodel in collectionviewsource ended in 1 thing: the application closes without error. don't know if because i'm attempting perform these tasks on mulithreaded collection, or if it's else.
either way, i'm not able figure out how top item sorted view. before used collectionviewsource, programatically sorting , building new list, grab first one. isn't possible since i'm updating instead of rebuilding.
do have ideas other me copying collection, sorting it, store first viewmodel, , tossing sorted copy?
edit 1
i attempted #1 , 2 again. both, error occurs on getting view after second item added collection, appears work after first item added. it's similar error occurred when trying update regular observablecollection item (and led me multithreaded version).
collectionviewsource.getdefaultview(askdepthasync)
error: [error.initialization.failed] notsupportedexception, type of collectionview not support changes sourcecollection thread different dispatcher thread., @ system.windows.data.collectionview.oncollectionchanged(object sender, notifycollectionchangedeventargs args) @ (mynamespace).mtobservablecollection`1.oncollectionchanged(notifycollectionchangedeventargs e) in c:\path\to\class\mtobservablecollection.cs:line 34 @ (mynamespace).mtobservablecollection`1.c__displayclass9.b__4() in c:\path\to\class\mtobservablecollection.cs:line 29 targetinvocationexception, exception has been thrown target of invocation. [...]
so, i'm multithreading error. call made in same event thread alters collection: event >> alter collection >> get 1st sorted item >> update big button properties.
edit 2
as usual, keep hammering @ thing try work. job @ stake here. i've managed come this:
this.dispatcher.invoke(dispatcherpriority.normal, new dispatcheroperationcallback(delegate { //icollectionview view = collectionviewsource.getdefaultview(((mybaseviewmodel)this.datacontext).askdepthasync); icollectionview view = collectionviewsource.getdefaultview(this.askdepthlist.itemssource); ienumerable<depthlevelviewmodel> col = view.cast<depthlevelviewmodel>(); list<depthlevelviewmodel> list = col.tolist(); ((mybaseviewmodel)this.datacontext).askdepthcurrent = list[0]; return null; }), null);
the commented-out line retrieve collection , go through whole call without problem. but, it's missing sorting, 0 index still first item in original collection. can breakpoint , see doesn't have sort descriptions. uncommented line uses itemssource
pull correct one.
view
contains right 1 sort descriptions , source collection.col
still hassortdescriptions
alongsourcelist
. list shows 1 entry ofdepthlevelviewmodel
type i'm casting to, enumeration empty.list
has 0 items duecol
having empty enumeration. therefore,list[0]
fails.
this happens if try retrieve collectionviewsource resources. feedback on this?
edit 2.1: if rid of col
, list
above , instead use this:
icollectionview view = collectionviewsource.getdefaultview(this.askdepthlist.itemssource); var col = view.getenumerator(); bool moved = col.movenext(); depthlevelviewmodel item = (depthlevelviewmodel)col.current; ((mybaseviewmodel)this.datacontext).askdepthcurrent = item;
col
still empty. shows 0 items, moved
false, , col.current
fails.
edit 3
it looks i'm going have fall on sorting collection manually , leave collectionviewsource
alone.
ienumerable<depthlevelviewmodel> depthquery = ((mybaseviewmodel)this.datacontext).askdepthasync.orderby(d => d.quotepricedouble); list<depthlevelviewmodel> depthlist = depthquery.tolist<depthlevelviewmodel>(); depthlevelviewmodel item = depthlist[0]; ((mybaseviewmodel)this.datacontext).askdepthcurrent = item;
since not ideal method, i'm leaving post unanswered. but, suffice until permanent solution found.
edit 4
i have migrated solution vs2015 , upgraded framework every project 4.6. if know newer work, i'd love hear it.
this may not optimal, it's thing i've managed works better re-sort.
in tab content control (view) has collectionviewsource
defined , parent datacontext
used across functionality (various views, tab manager, etc), added this:
void tabitemcontrol_datacontextchanged(object sender, dependencypropertychangedeventargs e) { ((tabviewmodel)datacontext).askcollection = (collectionviewsource)resources["askdepthcollection"]; ((tabviewmodel)datacontext).bidcollection = (collectionviewsource)resources["biddepthcollection"]; }
this stores reference sorted collections used on tab. in tab manager, put:
private function getfirstquote(byval etype bridgetraderbuyindicator) depthlevelviewmodel dim cview icollectionview dim csource collectionviewsource dim retview depthlevelviewmodel = nothing if etype = bridgetraderbuyindicator.buy csource = multilegviewmodel.askcollection else csource = multilegviewmodel.bidcollection end if try cview = csource.view() dim enumerator ienumerator = cview.cast(of depthlevelviewmodel).getenumerator() dim moved boolean = enumerator.movenext() if moved retview = directcast(enumerator.current(), depthlevelviewmodel) else applicationmodel.logger.writetolog((new stackframe(0).getmethod().name) & ": error - unable retrieve first quote.", loggerconstants.loglevel.heavy) end if catch ex exception applicationmodel.appmsgbox.debugmsg(ex, (new stackframe(0).getmethod().name)) end try return retview end function
when need first item, call this:
dim ask depthlevelviewmodel ask = getfirstquote(mytypeenum.buy)
if better solution isn't provided, i'll mark 1 accepted answer.
Comments
Post a Comment