/// <summary> /// Pauses until an <see cref="IObservableBooleanInput"/> changes its value and return the new value, using /// events (no polling). /// </summary> /// <param name="input">The input which shall be awaited.</param> /// <param name="value">The value that the input shall have before this method returns.</param> /// <param name="edgeOnly">If false, this method returns immediately if the desired <paramref name="value"/> is /// already present. If true, only a change from another value than <paramref name="value"/> to /// <paramref name="value"/> will cause the method to return.</param> /// <remarks> /// This is a blocking method. /// </remarks> public static bool WaitForChange(this IObservableBooleanInput input) { if (input == null) { throw new ArgumentNullException(nameof(input)); } // The signal being set when the desired value is reached: ManualResetEvent valueReached = new ManualResetEvent(false); // Handles the input.ValueChanged event. void ValueChangedHandler(object sender, bool newValue) { valueReached.Set(); } // Attach the event handler: input.ValueChanged += ValueChangedHandler; try { // Wait (blocking) for the event handler to set the signal: valueReached.WaitOne(); return(input.Value); } finally { // Remove the event handler: input.ValueChanged -= ValueChangedHandler; } }
public static void Run(IObservableBooleanInput button, IBooleanOutput lamp) { // Check arguments: if (button == null) { throw new ArgumentNullException(nameof(button)); } if (lamp == null) { throw new ArgumentNullException(nameof(lamp)); } // Store the lamp so that the event handler can use it: _lamp = lamp; // Attach the event handler to the event that the button raises whenever it's Value changed: button.ValueChanged += ButtonValueChangedHandler; // Set the lamp to its initial state, as the event will raise not earlier than when the input changes: lamp.Value = button.Value; // Just wait and let the event handler react on button changes: for (; ;) { Thread.Sleep(1000); } }
/// <summary> /// Waits for a button to turn from false to true, then turns a lamp on, and after that turns the lamp on or off /// on every change of the button. /// </summary> /// <param name="button">The button to use.</param> /// <param name="lamp">The lamp to use.</param> public static void Run(IObservableBooleanInput button, IBooleanOutput lamp) { // Check parameters: if (button == null) { throw new ArgumentNullException(nameof(button)); } if (lamp == null) { throw new ArgumentNullException(nameof(lamp)); } // Wait for the button to turn from false to true (test this holding the button when the program starts!): button.WaitFor(true, true); lamp.Value = true; // Wait for the button to change to any value and set the lamp accordingly. while (true) { lamp.Value = button.WaitForChange(); } }
/// <summary> /// Pauses until an <see cref="IObservableBooleanInput"/> returns a specified value, using events (no polling), /// optionally waiting only for an edge (that is, changing from another than the desired value to the desired /// value). /// </summary> /// <param name="input">The input which shall be awaited.</param> /// <param name="value">The value that the input shall have before this method returns.</param> /// <param name="edgeOnly">If false, this method returns immediately if the desired <paramref name="value"/> is /// already present. If true, only a change from another value than <paramref name="value"/> to /// <paramref name="value"/> will cause the method to return.</param> /// <remarks> /// This is a blocking method. /// </remarks> public static void WaitFor(this IObservableBooleanInput input, bool value, bool edgeOnly) { if (input == null) { throw new ArgumentNullException(nameof(input)); } // Only wait if the desired value is not already present and we do not wait for an edge: if (edgeOnly || (input.Value != value)) { // The signal being set when the desired value is reached: ManualResetEvent valueReached = new ManualResetEvent(false); // Handles the input.ValueChanged event. void ValueChangedHandler(object sender, bool newValue) { if (newValue == value) { valueReached.Set(); } } // Attach the event handler: input.ValueChanged += ValueChangedHandler; try { // Wait (blocking) for the event handler to set the signal: valueReached.WaitOne(); } finally { // Remove the event handler: input.ValueChanged -= ValueChangedHandler; } } }
/// <summary> /// Creates a <see cref="IObservableBooleanInput"/> using the specified source input. /// </summary> /// <param name="source">The input which shall be inverted.</param> /// <returns>The inverted input.</returns> /// <remarks>For instance, if you have an <see cref="IBooleanInput"/> object named "input", you can just code /// input.Invert() to get an inverted version of input.</remarks> public static IObservableBooleanInput Invert(this IObservableBooleanInput source) { return(new BooleanInvertObserverableInput(source)); }
/// <summary> /// Pauses until an <see cref="IObservableBooleanInput"/> has already or changes to a specified value, using /// events (no polling). /// </summary> /// <param name="input">The input which shall be awaited.</param> /// <param name="value">The value that the input shall have before this method returns.</param> /// <remarks> /// This is a blocking method. It will return immediately if the <paramref name="input"/> already has the /// desired <paramref name="value"/>, that is, it will not wait for an edge. /// </remarks> public static void WaitFor(this IObservableBooleanInput input, bool value) { WaitFor(input, value, false); }
/// <summary> /// Creates an instance. /// </summary> /// <param name="source">The input to be converted.</param> public BooleanInvertObserverableInput(IObservableBooleanInput source) { _source = source ?? throw new ArgumentNullException(nameof(source)); _source.ValueChanged += SourceValueChangedHandler; }