2

I have a specific scenario for this question, but a good generic solution should apply to many situations:

I have a WPF ItemsControl whose item's IsSelected property is data bound to a corresponding property in the view model. I then have a computationally intensive routine that runs (on a background thread) on the items that are selected. The problem is that if I trigger the computationally intensive task on changes to the IsSelected property of an item, then when multiple items are selected all at once, the computationally intensive task runs one time per item selected, rather than just one time after all the items have been selected, which is all it needs to do, and so it ends up taking significantly more processor time than is really neccessary.

IEnumerable<MyObject> items;

...

void IsSelectedPropertyChangedListener(object sender, PropertyChangedEventArgs e)
{
    if(e.PropertyName == "IsSelected")
        DoSomeIntensiveCalculation(items.Where(t=>t.IsSelected));
}

void DoSomeIntensiveCalculation(IEnumerable<MyObject> itemsToCalculate)
{
    ...
}

Of course I could just register the SelectionChanged event of the ItemsControl and trigger off of that since it is only called once per selection change even if multiple items are selected, but that is kind of violating MVVM, and there are other situations that a generic solution could apply to, that wouldn't have such an easy work around. (If you have a good argument for why in this particular situation I should do it like this, because it's better than any alternative, I'm willing to listen)

Another example I can think of is perhaps you have an ObservableCollection that you want to compute something difficult on each time it changes. Naturally you would register the CollectionChanged event to trigger your computation, but suppose something is adding a large number of items to the collection all at once, you really only need to do your computation one time once all the items have been added, doing it for each item being added would drastically reduce performance.

I could block the intensive task from running if another instance has already started running, simply setting a flag for it to run one more time when it finishes, this would cause it to only run twice even if a bunch of things were selected all at once, but that is still one time more than is really neccessary.

I could kill already running instances of the task each time a new one is started, but this would require adding a lot code to the computation task to gracefully stop itself when requested. It would also not work for situations where the intensive task is out my control (i.e. it's in a third party library and there is no graceful stopping mechanism provided).

Dave M
  • 2,863
  • 1
  • 22
  • 17
  • 2
    Look into [Reactive Extensions (Rx)](http://msdn.microsoft.com/en-us/data/gg577609.aspx), specifically buffering as described [here](http://stackoverflow.com/questions/10927298/reactive-extensions-process-events-in-batches-add-delay-between-every-batch). Rx can be hooked to incoming WPF events and expose them as a stream for you to operate against. – Adam Houldsworth Jul 24 '13 at 13:38
  • [This answer](http://stackoverflow.com/a/17818922/1136211) may give you an idea. – Clemens Jul 24 '13 at 13:50

1 Answers1

0

Not 100% sure what you are asking but here are some ideas:

  1. Use Task Parallel Library. The Task mananager will decide whether or not to launch a thread.
  2. Use a blocking queue .
  3. Redesign the interface to have a compute button
  4. Cache the result after the first computation.
Curtis White
  • 6,213
  • 12
  • 59
  • 83
  • 2
    If you're not even sure what is being asked you really shouldn't be posting an answer. If you have just a few basic concepts, such as this, you should be posting them as comments, rather than as an answer. – Servy Sep 18 '13 at 14:11