Created
March 22, 2017 18:10
-
-
Save pmunin/1602be25472b8c6886275d6f7e7fce03 to your computer and use it in GitHub Desktop.
Event Accumulator class
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using System.Text; | |
| using System.Threading; | |
| using System.Threading.Tasks; | |
| namespace EventAccumulatorUtils | |
| { | |
| /// <summary> | |
| /// Helper that allows to accumulate and temporary ignore events (e.g. PropertyChanged, Dirty,...) | |
| /// Has 2 main methods: BeginAccumulate, BeginIgnore | |
| /// </summary> | |
| public class EventAccumulator | |
| { | |
| public EventAccumulator() | |
| { | |
| } | |
| public EventAccumulator(Action<EventAccumulator> onInvoke) | |
| { | |
| OnInvoke(onInvoke); | |
| } | |
| Action<EventAccumulator> OnAccumulatorFlush; | |
| public IDisposable BeginAccumulate() | |
| { | |
| return new DisposeAction(a => { | |
| Interlocked.Increment(ref accumulate_Stack); | |
| a.OnDispose = () => { | |
| Interlocked.Decrement(ref accumulate_Stack); | |
| if (accumulate_Stack == 0) | |
| InvokeOrAccumulateOrIgnore(false); | |
| }; | |
| }); | |
| } | |
| public IDisposable BeginIgnore() | |
| { | |
| return new DisposeAction(a => { | |
| Interlocked.Increment(ref ignore_Stack); | |
| a.OnDispose = () => { | |
| Interlocked.Decrement(ref ignore_Stack); | |
| }; | |
| }); | |
| } | |
| public object AccumulatedData = null; | |
| int accumulated_Count = 0; | |
| public int Accumulated_Count => accumulated_Count; | |
| int accumulate_Stack = 0; | |
| int ignore_Stack = 0; | |
| public void Reset() | |
| { | |
| accumulated_Count = 0; | |
| accumulate_Stack = 0; | |
| ignore_Stack = 0; | |
| AccumulatedData = null; | |
| } | |
| public bool ShouldIgnore() | |
| { | |
| return ignore_Stack > 0; | |
| } | |
| /// <summary> | |
| /// Configure invocation | |
| /// </summary> | |
| /// <param name="onAccumulatorFlush"></param> | |
| public void OnInvoke(Action<EventAccumulator> onAccumulatorFlush) | |
| { | |
| OnAccumulatorFlush = onAccumulatorFlush; | |
| } | |
| /// <summary> | |
| /// Depending on the state (BeginAccumulate, BeginIgnore) it can either: | |
| /// Do nothing (if BeginIgnored started), | |
| /// or Append to accumulator (if BeginAccumulate started) | |
| /// or Invoke immediately if (neither BeginIgnore nor BeginAccumulate are started) | |
| /// </summary> | |
| public void InvokeOrAccumulateOrIgnore(bool incrementAccumulatedCount=true) | |
| { | |
| if (ignore_Stack > 0) | |
| return; | |
| if(incrementAccumulatedCount) | |
| Interlocked.Increment(ref accumulated_Count); | |
| if (accumulate_Stack > 0) | |
| return; | |
| if(accumulated_Count>0) | |
| OnAccumulatorFlush?.Invoke(this); | |
| Reset(); | |
| } | |
| } | |
| public class EventAccumulator<T>:EventAccumulator | |
| { | |
| public EventAccumulator() | |
| { | |
| } | |
| public EventAccumulator(Action<EventAccumulator<T>> onInvoke) | |
| { | |
| OnInvoke(e => onInvoke((EventAccumulator<T>)e)); | |
| } | |
| public new T AccumulatedData { get { return (T)base.AccumulatedData; } set { base.AccumulatedData = value; } } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment