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.

  1. create firstinview extension based on this post. tried using within parent viewmodel, within tab manager, calling mycollectionproperty.firstinview().
  2. tried access using examples this post.
  3. attempted use movecurrenttofirst mentioned in post.
  4. 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 has sortdescriptions along sourcelist. list shows 1 entry of depthlevelviewmodel type i'm casting to, enumeration empty.
  • list has 0 items due col 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

Popular posts from this blog

java - Static nested class instance -

c# - Bluetooth LE CanUpdate Characteristic property -

JavaScript - Replace variable from string in all occurrences -