public void TestLoopCell() { DiscreteCellSink <int> ca = DiscreteCell.CreateSink(22); ValueTuple <DiscreteCellLoop <int>, DiscreteCell <int>, DiscreteCell <int> > c = Transaction.Run(() => { DiscreteCellLoop <int> cbLocal = DiscreteCell.CreateLoop <int>(); DiscreteCell <int> ccLocal = ca.Map(x => x % 10).Lift(cbLocal, (x, y) => x * y); DiscreteCell <int> cbOut = ca.Map(x => x / 10); cbLocal.Loop(cbOut); return(ValueTuple.Create(cbLocal, cbOut, ccLocal)); }); DiscreteCellLoop <int> cb = c.Item1; DiscreteCell <int> cb2 = c.Item2; DiscreteCell <int> cc = c.Item3; List <int> @out = new List <int>(); List <int> out2 = new List <int>(); List <int> out3 = new List <int>(); IListener l = cb.Listen(@out.Add); IListener l2 = cb2.Listen(out2.Add); IListener l3 = cc.Listen(out3.Add); ca.Send(2); ca.Send(52); l3.Unlisten(); l2.Unlisten(); l.Unlisten(); CollectionAssert.AreEqual(new[] { 2, 0, 5 }, @out.ToArray()); CollectionAssert.AreEqual(new[] { 2, 0, 5 }, out2.ToArray()); CollectionAssert.AreEqual(new[] { 4, 0, 10 }, out3.ToArray()); }
public void TestSwitchCSimultaneous() { Sc2 sc1 = new Sc2(0); DiscreteCellSink <Sc2> csc = DiscreteCell.CreateSink(sc1); DiscreteCell <int> co = csc.Map <DiscreteCell <int> >(b => b.C).SwitchC(); List <int> @out = new List <int>(); IListener l = co.Listen(@out.Add); Sc2 sc2 = new Sc2(3); Sc2 sc3 = new Sc2(4); Sc2 sc4 = new Sc2(7); sc1.C.Send(1); sc1.C.Send(2); csc.Send(sc2); sc1.C.Send(3); sc2.C.Send(4); sc3.C.Send(5); csc.Send(sc3); sc3.C.Send(6); sc3.C.Send(7); Transaction.RunVoid(() => { sc3.C.Send(2); csc.Send(sc4); sc4.C.Send(8); }); sc4.C.Send(9); l.Unlisten(); CollectionAssert.AreEqual(new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, @out); }
public void Run() { DiscreteCellSink <int> x = new DiscreteCellSink <int>(0); IListener l = x.Listen(Console.WriteLine); x.Send(10); x.Send(20); x.Send(30); l.Unlisten(); }
public void TestDiscreteCellValuesThenOnce() { DiscreteCellSink <int> c = DiscreteCell.CreateSink(9); List <int> @out = new List <int>(); IListener l = Transaction.Run(() => c.Values.Once().Listen(@out.Add)); c.Send(2); c.Send(7); l.Unlisten(); CollectionAssert.AreEqual(new[] { 9 }, @out); }
public void TestListen() { DiscreteCellSink <int> c = DiscreteCell.CreateSink(9); List <int> @out = new List <int>(); IListener l = c.Listen(@out.Add); c.Send(2); c.Send(7); l.Unlisten(); CollectionAssert.AreEqual(new[] { 9, 2, 7 }, @out); }
public void TestMapLateListen() { DiscreteCellSink <int> c = DiscreteCell.CreateSink(6); List <string> @out = new List <string>(); DiscreteCell <string> cm = c.Map(x => x.ToString()); c.Send(2); IListener l = cm.Listen(@out.Add); c.Send(8); l.Unlisten(); CollectionAssert.AreEqual(new[] { "2", "8" }, @out); }
public void TestLiftSimultaneousUpdates() { List <int> @out = new List <int>(); DiscreteCellSink <int> cellSink = DiscreteCell.CreateSink(1); DiscreteCell <int> cell = cellSink.Map(v => 2 * v); IListener l = cellSink.Lift(cell, (x, y) => x + y).Updates.Listen(@out.Add); cellSink.Send(2); cellSink.Send(7); l.Unlisten(); CollectionAssert.AreEqual(new[] { 6, 21 }, @out); }
public void TestDiscreteCellValuesThenLateListen() { DiscreteCellSink <int> c = DiscreteCell.CreateSink(9); List <int> @out = new List <int>(); Stream <int> value = c.Values; c.Send(8); IListener l = value.Listen(@out.Add); c.Send(2); c.Send(7); l.Unlisten(); CollectionAssert.AreEqual(new[] { 2, 7 }, @out); }
public FrView(Window window, Fridget fr, IListener l) { StreamSink <MouseEvent> sMouse = new StreamSink <MouseEvent>(); StreamSink <KeyEvent> sKey = new StreamSink <KeyEvent>(); this.MouseDown += (sender, args) => sMouse.Send(new MouseEvent(args, () => args.GetPosition(this))); this.MouseUp += (sender, args) => sMouse.Send(new MouseEvent(args, () => args.GetPosition(this))); this.MouseMove += (sender, args) => sMouse.Send(new MouseEvent(args, () => args.GetPosition(this))); DiscreteCellSink <Maybe <Size> > size = new DiscreteCellSink <Maybe <Size> >(Maybe.None); this.SizeChanged += (sender, args) => size.Send(Maybe.Some(args.NewSize)); window.KeyDown += (sender, args) => { Key key = args.Key == Key.System ? args.SystemKey : args.Key; if (key == Key.Back) { sKey.Send(new BackspaceKeyEvent()); } }; window.TextInput += (sender, args) => sKey.Send(new StringKeyEvent(args.Text)); DiscreteCellLoop <long> focus = new DiscreteCellLoop <long>(); Fridget.Output fo = fr.Reify(size, sMouse, sKey, focus, new Supply()); focus.Loop(fo.SChangeFocus.Hold(-1)); this.drawable = fo.Drawable; this.l = new CompositeListener(new[] { l, this.drawable.Updates.Listen(d => this.InvalidateVisual()) }); }
public void TestDiscreteCellValuesThenMerge() { DiscreteCellSink <int> c1 = DiscreteCell.CreateSink(9); DiscreteCellSink <int> c2 = DiscreteCell.CreateSink(2); List <int> @out = new List <int>(); IListener l = Transaction.Run(() => c1.Values.Merge(c2.Values, (x, y) => x + y).Listen(@out.Add)); c1.Send(1); c2.Send(4); Transaction.RunVoid(() => { c1.Send(7); c2.Send(5); }); l.Unlisten(); CollectionAssert.AreEqual(new[] { 11, 1, 4, 12 }, @out); }
public async Task TestListenAsync() { DiscreteCellSink <int> a = DiscreteCell.CreateSink(1); DiscreteCell <int> a1 = a.Map(x => x + 1); DiscreteCell <int> a2 = a.Map(x => x * 2); ValueTuple <List <int>, DiscreteCellLoop <int>, IListener> resultsAndCalled = Transaction.Run(() => { DiscreteCell <int> result = a1.Lift(a2, (x, y) => x + y); Stream <Unit> incrementStream = Operational.Value(result.Cell).MapTo(Unit.Value); StreamSink <Unit> decrementStream = Stream.CreateSink <Unit>(); DiscreteCellLoop <int> calledLoop = DiscreteCell.CreateLoop <int>(); calledLoop.Loop(incrementStream.MapTo(1).Merge(decrementStream.MapTo(-1), (x, y) => x + y).Snapshot(calledLoop.Cell, (u, c) => c + u).Hold(0)); List <int> r = new List <int>(); IListener l = result.Listen(v => { Task.Run(async() => { await Task.Delay(900); r.Add(v); decrementStream.Send(Unit.Value); }); }); return(ValueTuple.Create(r, calledLoop, l)); }); // ReSharper disable once UnusedVariable List <int> results = resultsAndCalled.Item1; DiscreteCell <int> called = resultsAndCalled.Item2; List <int> calledResults = new List <int>(); IListener l2 = called.Listen(calledResults.Add); await Task.Delay(500); a.Send(2); await Task.Delay(500); a.Send(3); await Task.Delay(2500); l2.Unlisten(); resultsAndCalled.Item3.Unlisten(); }
public STextField(string initialText) { base.Text = initialText; DiscreteCellSink <string> text = new DiscreteCellSink <string>(initialText); this.TextChanged += async(sender, args) => { string t = base.Text; await Task.Run(() => text.Send(t)); }; this.Text = text; }
public void TestLift() { DiscreteCellSink <int> c1 = DiscreteCell.CreateSink(1); DiscreteCellSink <long> c2 = DiscreteCell.CreateSink(5L); List <string> @out = new List <string>(); IListener l = c1.Lift(c2, (x, y) => x + " " + y).Listen(@out.Add); c1.Send(12); c2.Send(6L); l.Unlisten(); CollectionAssert.AreEqual(new[] { "1 5", "12 5", "12 6" }, @out); }
public void TestApply() { DiscreteCellSink <Func <long, string> > cf = DiscreteCell.CreateSink <Func <long, string> >(x => "1 " + x); DiscreteCellSink <long> ca = DiscreteCell.CreateSink(5L); List <string> @out = new List <string>(); IListener l = ca.Apply(cf).Listen(@out.Add); cf.Send(x => "12 " + x); ca.Send(6L); l.Unlisten(); CollectionAssert.AreEqual(new[] { "1 5", "12 5", "12 6" }, @out); }
public void TestLiftGlitch() { DiscreteCellSink <int> c1 = DiscreteCell.CreateSink(1); DiscreteCell <int> c3 = c1.Map(x => x * 3); DiscreteCell <int> c5 = c1.Map(x => x * 5); DiscreteCell <string> c = c3.Lift(c5, (x, y) => x + " " + y); List <string> @out = new List <string>(); IListener l = c.Listen(@out.Add); c1.Send(2); l.Unlisten(); CollectionAssert.AreEqual(new[] { "3 5", "6 10" }, @out); }
public static void Main2(string[] args) { Console.WriteLine("Press any key"); Console.ReadKey(); //DiscreteCellSink<IReadOnlyList<SmallTestObject>> s = ((Func<DiscreteCellSink<IReadOnlyList<SmallTestObject>>>)(() => // new DiscreteCellSink<IReadOnlyList<SmallTestObject>>(new SmallTestObject[0])))(); DiscreteCellSink <IReadOnlyList <SmallTestObject> > s = ((Func <DiscreteCellSink <IReadOnlyList <SmallTestObject> > >)(() => new DiscreteCellSink <IReadOnlyList <SmallTestObject> >(Enumerable.Range(0, 500).Select(_ => new SmallTestObject()).ToArray())))(); DiscreteCell <IReadOnlyList <bool> > s2 = s.Map(oo => oo.Select(o => o.S).Lift()).SwitchC(); ((Action)(() => { for (int i = 0; i < 5; i++) { s.Send(Enumerable.Range(0, 500).Select(_ => new SmallTestObject()).ToArray()); } }))(); s.Send(new SmallTestObject[0]); Console.WriteLine("Press any key"); Console.ReadKey(); ((Action)(() => { for (int i = 0; i < 5; i++) { s.Send(Enumerable.Range(0, 500).Select(_ => new SmallTestObject()).ToArray()); } }))(); s.Send(new SmallTestObject[0]); Console.WriteLine("Press any key"); Console.ReadKey(); }
public void TestCalm() { DiscreteCellSink <int> c = DiscreteCell.CreateSink(2); List <int> @out = new List <int>(); IListener l = Transaction.Run(() => c.Calm().Listen(@out.Add)); c.Send(2); c.Send(2); c.Send(4); c.Send(2); c.Send(4); c.Send(4); c.Send(2); c.Send(2); l.Unlisten(); CollectionAssert.AreEqual(new[] { 2, 4, 2, 4, 2 }, @out); }
public void TestLiftFromSimultaneous() { ValueTuple <DiscreteCellSink <int>, DiscreteCellSink <int> > t = Transaction.Run(() => { DiscreteCellSink <int> localC1 = DiscreteCell.CreateSink(3); DiscreteCellSink <int> localC2 = DiscreteCell.CreateSink(5); localC2.Send(7); return(ValueTuple.Create(localC1, localC2)); }); DiscreteCellSink <int> c1 = t.Item1; DiscreteCellSink <int> c2 = t.Item2; List <int> @out = new List <int>(); IListener l = c1.Lift(c2, (x, y) => x + y).Listen(@out.Add); l.Unlisten(); CollectionAssert.AreEqual(new[] { 10 }, @out); }
public void Run() { DiscreteCellSink <int> sa = new DiscreteCellSink <int>(1); IListener l = Calm(sa).Listen(Console.WriteLine); sa.Send(1); sa.Send(2); sa.Send(2); sa.Send(4); sa.Send(4); sa.Send(1); l.Unlisten(); }
public void TestLiftInSwitchC() { IReadOnlyList <Test> list1 = new[] { new Test(0), new Test(1), new Test(2), new Test(3), new Test(4) }; IReadOnlyList <Test> list2 = new[] { new Test(5), new Test(6), new Test(7), new Test(8), new Test(9) }; DiscreteCellSink <IReadOnlyList <Test> > v = DiscreteCell.CreateSink(list1); DiscreteCell <IReadOnlyList <int> > c = v.Map(oo => oo.Select(o => o.Value).Lift()).SwitchC(); List <IReadOnlyList <int> > streamOutput = new List <IReadOnlyList <int> >(); IListener l = c.Updates.Listen(streamOutput.Add); List <IReadOnlyList <int> > cellOutput = new List <IReadOnlyList <int> >(); IListener l2 = c.Listen(cellOutput.Add); list1[2].Value.Send(12); list2[1].Value.Send(16); list1[4].Value.Send(14); Transaction.RunVoid(() => { list2[2].Value.Send(17); list1[0].Value.Send(10); v.Send(list2); }); list1[3].Value.Send(13); list2[3].Value.Send(18); l2.Unlisten(); l.Unlisten(); Assert.AreEqual(4, streamOutput.Count); Assert.AreEqual(5, cellOutput.Count); CollectionAssert.AreEqual(new[] { 0, 1, 2, 3, 4 }, cellOutput[0]); CollectionAssert.AreEqual(new[] { 0, 1, 12, 3, 4 }, streamOutput[0]); CollectionAssert.AreEqual(new[] { 0, 1, 12, 3, 4 }, cellOutput[1]); CollectionAssert.AreEqual(new[] { 0, 1, 12, 3, 14 }, streamOutput[1]); CollectionAssert.AreEqual(new[] { 0, 1, 12, 3, 14 }, cellOutput[2]); CollectionAssert.AreEqual(new[] { 5, 16, 17, 8, 9 }, streamOutput[2]); CollectionAssert.AreEqual(new[] { 5, 16, 17, 8, 9 }, cellOutput[3]); CollectionAssert.AreEqual(new[] { 5, 16, 17, 18, 9 }, streamOutput[3]); CollectionAssert.AreEqual(new[] { 5, 16, 17, 18, 9 }, cellOutput[4]); }
public void Run() { DiscreteCellSink <double> mainClock = new DiscreteCellSink <double>(0.0); StreamSink <Unit> sPause = new StreamSink <Unit>(); StreamSink <Unit> sResume = new StreamSink <Unit>(); DiscreteCell <double> gameClock = PausableClock(sPause, sResume, mainClock); IListener l = mainClock.Lift(gameClock, (m, g) => "main=" + m + " game=" + g).Listen(Console.WriteLine); mainClock.Send(1.0); mainClock.Send(2.0); mainClock.Send(3.0); sPause.Send(Unit.Value); mainClock.Send(4.0); mainClock.Send(5.0); mainClock.Send(6.0); sResume.Send(Unit.Value); mainClock.Send(7.0); l.Unlisten(); }
public void SwitchCCatchFirst() { List <int> output = new List <int>(); ValueTuple <DiscreteCell <int>, DiscreteCellSink <int>, DiscreteCellSink <int>, DiscreteCellSink <DiscreteCell <int> >, IListener> t = Transaction.Run(() => { DiscreteCellSink <int> c1 = DiscreteCell.CreateSink(1); DiscreteCellSink <int> c2 = DiscreteCell.CreateSink(11); DiscreteCellSink <DiscreteCell <int> > s = DiscreteCell.CreateSink(c1.AsDiscreteCell()); DiscreteCell <int> c = s.SwitchC(); c1.Send(2); c2.Send(12); s.Send(c2); IListener l = c.Listen(output.Add); return(ValueTuple.Create(c, c1, c2, s, l)); }); t.Item2.Send(3); t.Item3.Send(13); Transaction.RunVoid(() => { t.Item2.Send(4); t.Item3.Send(14); t.Item4.Send(t.Item2); }); t.Item2.Send(5); t.Item3.Send(15); t.Item5.Unlisten(); CollectionAssert.AreEqual(new[] { 12, 13, 4, 5 }, output); }
private static void SendMore(DiscreteCellSink <IReadOnlyList <TestObject> > cellSink, Stream <bool> selectAllStream) { Transaction.RunConstructVoid(() => cellSink.Send(Enumerable.Range(0, 20000).Select(n => new TestObject(n, selectAllStream)).ToArray())); }
public Implementation(PetrolPumpWindow petrolPump) { SComboBox <IPump> logic = new SComboBox <IPump>( new IPump[] { new LifeCyclePump(), new AccumulatePulsesPump(), new ShowDollarsPump(), new ClearSalePump(), new KeypadPump(), new PresetAmountPump() }, p => p.GetType().FullName); petrolPump.LogicComboBoxPlaceholder.Children.Add(logic); STextField textPrice1 = new STextField("2.149") { Width = 100 }; petrolPump.Price1Placeholder.Children.Add(textPrice1); STextField textPrice2 = new STextField("2.341") { Width = 100 }; petrolPump.Price2Placeholder.Children.Add(textPrice2); STextField textPrice3 = new STextField("1.499") { Width = 100 }; petrolPump.Price3Placeholder.Children.Add(textPrice3); Func <string, double> parseDoubleSafe = s => { double n; if (double.TryParse(s, out n)) { return(n); } return(0.0); }; StreamSink <Key> sKey = new StreamSink <Key>(); Dictionary <Key, FrameworkElement> containersByKey = new Dictionary <Key, FrameworkElement> { { Key.One, petrolPump.Keypad1Button }, { Key.Two, petrolPump.Keypad2Button }, { Key.Three, petrolPump.Keypad3Button }, { Key.Four, petrolPump.Keypad4Button }, { Key.Five, petrolPump.Keypad5Button }, { Key.Six, petrolPump.Keypad6Button }, { Key.Seven, petrolPump.Keypad7Button }, { Key.Eight, petrolPump.Keypad8Button }, { Key.Nine, petrolPump.Keypad9Button }, { Key.Zero, petrolPump.Keypad0Button }, { Key.Clear, petrolPump.KeypadClearButton } }; foreach (KeyValuePair <Key, FrameworkElement> containerAndKey in containersByKey) { containerAndKey.Value.MouseDown += async(sender, args) => { if (args.LeftButton == MouseButtonState.Pressed) { await Task.Run(() => sKey.Send(containerAndKey.Key)); } }; } DiscreteCellLoop <UpDown> nozzle1 = new DiscreteCellLoop <UpDown>(); DiscreteCellLoop <UpDown> nozzle2 = new DiscreteCellLoop <UpDown>(); DiscreteCellLoop <UpDown> nozzle3 = new DiscreteCellLoop <UpDown>(); DiscreteCell <double> calibration = DiscreteCell.Constant(0.001); DiscreteCell <double> price1 = textPrice1.Text.Map(parseDoubleSafe); DiscreteCell <double> price2 = textPrice2.Text.Map(parseDoubleSafe); DiscreteCell <double> price3 = textPrice3.Text.Map(parseDoubleSafe); DiscreteCellSink <Stream <Unit> > csClearSale = new DiscreteCellSink <Stream <Unit> >(Sodium.Stream.Never <Unit>()); Stream <Unit> sClearSale = csClearSale.SwitchS(); StreamSink <int> sFuelPulses = new StreamSink <int>(); Cell <Outputs> outputs = logic.SelectedItem.Map( pump => pump.Create(new Inputs( nozzle1.Updates, nozzle2.Updates, nozzle3.Updates, sKey, sFuelPulses, calibration, price1, price2, price3, sClearSale))); DiscreteCell <Delivery> delivery = outputs.Map(o => o.Delivery).SwitchC(); DiscreteCell <string> presetLcd = outputs.Map(o => o.PresetLcd).SwitchC(); DiscreteCell <string> saleCostLcd = outputs.Map(o => o.SaleCostLcd).SwitchC(); DiscreteCell <string> saleQuantityLcd = outputs.Map(o => o.SaleQuantityLcd).SwitchC(); DiscreteCell <string> priceLcd1 = outputs.Map(o => o.PriceLcd1).SwitchC(); DiscreteCell <string> priceLcd2 = outputs.Map(o => o.PriceLcd2).SwitchC(); DiscreteCell <string> priceLcd3 = outputs.Map(o => o.PriceLcd3).SwitchC(); Stream <Unit> sBeep = outputs.Map(o => o.SBeep).SwitchS(); Stream <Sale> sSaleComplete = outputs.Map(o => o.SSaleComplete).SwitchS(); SoundPlayer beepPlayer = new SoundPlayer(GetResourceStream(@"sounds\beep.wav")); this.listeners.Add(sBeep.Listen(_ => new Thread(() => beepPlayer.PlaySync()) { IsBackground = true }.Start())); SoundPlayer fastRumblePlayer = new SoundPlayer(GetResourceStream(@"sounds\fast.wav")); Action stopFast = () => { }; void PlayFast() { ManualResetEvent mre = new ManualResetEvent(false); new Thread(() => { fastRumblePlayer.PlayLooping(); mre.WaitOne(); fastRumblePlayer.Stop(); }) { IsBackground = true }.Start(); stopFast = () => { mre.Set(); stopFast = () => { }; }; } SoundPlayer slowRumblePlayer = new SoundPlayer(GetResourceStream(@"sounds\slow.wav")); Action stopSlow = () => { }; void PlaySlow() { ManualResetEvent mre = new ManualResetEvent(false); new Thread(() => { slowRumblePlayer.PlayLooping(); mre.WaitOne(); slowRumblePlayer.Stop(); }) { IsBackground = true }.Start(); stopSlow = () => { mre.Set(); stopSlow = () => { }; }; } this.listeners.Add(delivery.Changes().Listen(d => { petrolPump.Dispatcher.InvokeIfNecessary(() => { if (d == Delivery.Fast1 || d == Delivery.Fast2 || d == Delivery.Fast3) { PlayFast(); } else { stopFast(); } if (d == Delivery.Slow1 || d == Delivery.Slow2 || d == Delivery.Slow3) { PlaySlow(); } else { stopSlow(); } }); })); StackPanel presetLcdStackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.PresetPlaceholder.Children.Add(presetLcdStackPanel); this.listeners.Add(presetLcd.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(presetLcdStackPanel, t, 5, true)))); StackPanel saleCostStackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.DollarsPlaceholder.Children.Add(saleCostStackPanel); this.listeners.Add(saleCostLcd.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(saleCostStackPanel, t, 5, true)))); StackPanel saleQuantityLcdStackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.LitersPlaceholder.Children.Add(saleQuantityLcdStackPanel); this.listeners.Add(saleQuantityLcd.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(saleQuantityLcdStackPanel, t, 5, true)))); StackPanel priceLcd1StackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.Fuel1Placeholder.Children.Add(priceLcd1StackPanel); this.listeners.Add(priceLcd1.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(priceLcd1StackPanel, t, 5, false)))); StackPanel priceLcd2StackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.Fuel2Placeholder.Children.Add(priceLcd2StackPanel); this.listeners.Add(priceLcd2.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(priceLcd2StackPanel, t, 5, false)))); StackPanel priceLcd3StackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.Fuel3Placeholder.Children.Add(priceLcd3StackPanel); this.listeners.Add(priceLcd3.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(priceLcd3StackPanel, t, 5, false)))); Dictionary <DiscreteCellLoop <UpDown>, Image> nozzles = new Dictionary <DiscreteCellLoop <UpDown>, Image> { { nozzle1, petrolPump.Nozzle1Image }, { nozzle2, petrolPump.Nozzle2Image }, { nozzle3, petrolPump.Nozzle3Image } }; this.listeners.AddRange(nozzles.Select(nozzle => nozzle.Key.Listen(p => petrolPump.Dispatcher.InvokeIfNecessary(() => nozzle.Value.Margin = p == UpDown.Up ? new Thickness(0, 0, 0, 0) : new Thickness(0, 30, 0, 0))))); foreach (KeyValuePair <DiscreteCellLoop <UpDown>, Image> nozzle in nozzles) { StreamSink <Unit> nozzleClicks = new StreamSink <Unit>(); nozzle.Value.MouseDown += async(sender, args) => { if (args.LeftButton == MouseButtonState.Pressed) { await Task.Run(() => nozzleClicks.Send(Unit.Value)); } }; nozzle.Key.Loop(nozzleClicks.Snapshot(nozzle.Key, (_, n) => n == UpDown.Down ? UpDown.Up : UpDown.Down).Hold(UpDown.Down)); } this.listeners.Add(sSaleComplete.Listen(sale => { Task.Run(() => { petrolPump.Dispatcher.InvokeIfNecessary(() => { SaleCompleteDialog dialog = new SaleCompleteDialog( sale.Fuel.ToString(), Formatters.FormatPrice(sale.Price, null), Formatters.FormatSaleCost(sale.Cost), Formatters.FormatSaleQuantity(sale.Quantity)); dialog.Owner = petrolPump; csClearSale.Send(dialog.SOkClicked); dialog.Show(); IListener l = null; // ReSharper disable once RedundantAssignment l = dialog.SOkClicked.Listen(_ => { petrolPump.Dispatcher.InvokeIfNecessary(() => dialog.Close()); // ReSharper disable once AccessToModifiedClosure l?.Unlisten(); }); }); }); })); Task.Run(async() => { while (true) { Transaction.RunVoid(() => { switch (delivery.Cell.Sample()) { case Delivery.Fast1: case Delivery.Fast2: case Delivery.Fast3: sFuelPulses.Send(40); break; case Delivery.Slow1: case Delivery.Slow2: case Delivery.Slow3: sFuelPulses.Send(2); break; } }); await Task.Delay(200).ConfigureAwait(false); } // ReSharper disable once FunctionNeverReturns }); }