I want to await a button.click() event. For that created an extension GetAwaiter() method:
public static class ButtonAwaiterExtensions
{
public static ButtonAwaiter GetAwaiter(this Button button)
{
return new ButtonAwaiter()
{
Button = button
};
}
public class ButtonAwaiter : INotifyCompletion
{
public bool IsCompleted
{
get { return false; }
}
public void GetResult()
{
}
public Button? Button { get; set; }
public void OnCompleted(Action continuation)
{
RoutedEventHandler? h = null;
h = (o, e) =>
{
Button!.Click -= h;
continuation();
};
Button!.Click += h;
}
}
}
(I found it here: http://blog.roboblob.com/2014/10/23/awaiting-for-that-button-click/)
With that I can await the Button1.Click() event directly with await Button1; which is great.
BUT I couldn't figure out how to combine this awaitable with someting like await Task.WhenAny()
I tried
await Task.WhenAny(Button1, Button2);
It will tell me that it "cannot convert from Button to Task".
I thougt I found the solution here:
Using `Task.WhenAll` with `INotifyCompletion` by just adding a method
public static async Task GetTask()
{
await this;
}
to my ButtonAwaiterExtensions class, but the keyword this cannot be used in my static class.
I cannot figure out what to return in the method or generally how to await any Button.Click(). Any ideas?
Thanks to Sebastian Schumann comment (how can I combine await.WhenAny() with GetAwaiter extension method) I solved my problem by adding another extension method directly to my ButtonAwaiterExtensions class:
public async static Task AsTask(this Button self) => await self;
Complete solution:
public static class ButtonAwaiterExtensions
{
public static ButtonAwaiter GetAwaiter(this Button button)
{
return new ButtonAwaiter()
{
Button = button
};
}
public class ButtonAwaiter : INotifyCompletion
{
public bool IsCompleted
{
get { return false; }
}
public void GetResult()
{
}
public Button? Button { get; set; }
public void OnCompleted(Action continuation)
{
RoutedEventHandler? h = null;
h = (o, e) =>
{
Button!.Click -= h;
continuation();
};
Button!.Click += h;
}
}
public async static Task AsTask(this Button self) => await self;
}
An alternative (little shorter) Implementation for GetAwaiter might be:
public static TaskAwaiter GetAwaiter(this Button self)
{
ArgumentNullException.ThrowIfNull(self);
TaskCompletionSource tcs = new();
self.Click += OnClick;
return tcs.Task.GetAwaiter();
void OnClick(object sender, EventArgs args)
{
self.Click -= OnClick;
tcs.SetResult();
}
}
Related
I make a method called Instance that allow me to have a single instance of the Settings window, like this:
public static async Task<Settings> Instance()
{
if (AppWindow == null)
{
AppWindow = new Settings();
AppWindow.Closing += async (x, y) =>
{
bool close = await AppWindow.CheckSettings();
y.cancel = (close) ? true : false;
AppWindow = null;
};
}
return AppWindow;
}
the CheckSettings have this structure:
private async Task<bool> CheckSettings()
{
//just as example
return true;
}
the method Instance() tell me that there is no await operator inside. Why happen this?
I need to ask also other questions:
Can this logic used inside a property instead of Instance method? How?
Is possible close the window without implement a Task<bool>
UPDATE
based on the helpful answer and comments on this great community I have edited the method as this (now is a property):
public static Settings Instance
{
get
{
if (AppWindow == null)
{
AppWindow = new Settings();
AppWindow.Closing += async (x, y) =>
{
bool close = await AppWindow.CheckSettings();
y.Cancel = close;
//AppWindow.Close();
//AppWindow = null;
};
}
return AppWindow;
}
}
the problem is that the Cancel does not await the CheckSettings()
Set the Cancel property to true before you call your async method:
public static Settings Instance
{
get
{
if (AppWindow == null)
{
AppWindow = new Settings();
//attach the event handler
AppWindow.Closing += AppWindow_Closing;
}
return AppWindow;
}
}
private static async void AppWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
//call the async method
bool close = await AppWindow.CheckSettings();
if (close)
{
AppWindow win = (AppWindow)sender;
//detach the event handler
AppWindow.Closing -= AppWindow_Closing;
//...and close the window immediately
win.Close();
AppWindow = null;
}
}
Hi I have a problem testing an event using NUnit. I'm not even sure if this should be unit or functional test. Let me show you the sample class first (I'm trying to test OnValueInjected event):
public class Foo
{
private IBar CurrentBar { get; set; }
public event EventHandler<MoveEventArgs> OnValueInjected;
public Foo()
{
StartFoo();
}
private async void StartFoo()
{
await Task.Factory.StartNew(() =>
{
while (State != FooState.Finished)
{
IResult result = CurrentBar.WaitForValue(); // This is blocking function, wait for a value
OnValueInjected?.Invoke(this, new ResultEventArgs(result));
// .. rest of the loop
}
});
}
public void InjectValue(int a, int b)
{
CurrentBar.Inject(a,b);
}
}
So, basically what I'm trying to do is to subscribe to the event, call InjectValue and check if the event was called. Like this:
[Test]
public void FooOnValueInjectedTest()
{
bool OnValueInjectedWasRasied = false;
IFoo foo = new Foo();
foo.OnValueInjected += (s, e) => OnValueInjectedWasRasied = true;
foo.InjectValue(0,0);
Assert.AreEqual(true, OnValueInjectedWasRasied);
}
Pretty straightforward, BUT it looks like InjectValue is too slow. The test is failing..I think it's too slow, because when I add Thread.Sleep between InjectValue and Assert to works.
foo.InjectValue(0,0);
Thread.Sleep(1000);
Assert.AreEqual(true, OnValueInjectedWasRasied);
Is there a better way to test such an event? Thanks
I fixed my class, so it's like that now:
public class Foo
{
private AutoResetEvent AutoReset { get; }
private IBar CurrentBar { get; set; }
public event EventHandler<MoveEventArgs> OnValueInjected;
public Foo()
{
AutoReset = new AutoResetEvent(false);
StartFoo();
}
private async void StartFoo()
{
await Task.Factory.StartNew(() =>
{
while (State != FooState.Finished)
{
IResult result = CurrentBar.WaitForValue(); // This is blocking function, wait for a value
OnValueInjected?.Invoke(this, new ResultEventArgs(result));
AutoReset.Set();
// .. rest of the loop
}
});
}
public void InjectValue(int a, int b)
{
if (CurrentBar.Inject(a,b))
{
AutoReset.WaitOne();
}
}
}
I believe this is a problem of asynchronous calling. Whenever you have an async method in an NUnit test, it doesn't wait for it to be done as no one is actually waiting for it to be done and return the result. Instead, you have to do a .Wait on the async method to force the test to wait for it to be done.
I did not write this code in a code editor so it may not be perfect but that's the basic idea.
public class Foo
{
private AutoResetEvent AutoReset { get; }
private IBar CurrentBar { get; set; }
public event EventHandler<MoveEventArgs> OnValueInjected;
public Foo()
{
AutoReset = new AutoResetEvent(false);
StartFoo();
}
private async void StartFoo()
{
await Task.Factory.StartNew(() =>
{
while (State != FooState.Finished)
{
IResult result = CurrentBar.WaitForValue(); // This is blocking function, wait for a value
OnValueInjected?.Invoke(this, new ResultEventArgs(result));
AutoReset.Set();
// .. rest of the loop
}
});
}
public async void InjectValue(int a, int b)
{
if (CurrentBar.Inject(a,b))
{
AutoReset.WaitOne();
}
}
}
Then in your test method in the ACT you do a .Wait
[Test]
public void FooOnValueInjectedTest()
{
// Arrange
bool OnValueInjectedWasRasied = false;
IFoo foo = new Foo();
foo.OnValueInjected += (s, e) => OnValueInjectedWasRasied = true;
// Act
foo.InjectValue(0,0).Wait();
// Assert
Assert.AreEqual(true, OnValueInjectedWasRasied);
}
I have a viewModel with async Task. I don't now how to test it.
public class MyViewModel : BindableBase
{
public MyViewModel()
{
this.PropertyChanged += MyViewModel_PropertyChanged;
}
private void MyViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
Action action = async () => await DoSomething();
action();
}
public const string BeforeKey = "before";
public const string AfterKey = "After";
public string Status { get; private set; } = BeforeKey;
public async Task DoSomething()
{
await Task.Delay(3000);
Status = AfterKey;
}
string bindagleProp;
public string BindagleProp
{
get { return bindagleProp; }
set { SetProperty(ref bindagleProp, value); }
}
}
Here is my test:
[TestMethod]
public async Task TestMyViewModel()
{
MyViewModel viewModel = new MyViewModel();
Assert.AreEqual(viewModel.Status, MyViewModel.BeforeKey, "before check");
viewModel.BindagleProp = "abc";
Assert.AreEqual(viewModel.Status, MyViewModel.AfterKey, "after check");
}
The test failed because it's not waiting to completion of the task.
I DON'T want to use Task.Delay in the unit test, because it's not safety. DoSomething method can has unknown duration time.
Thank you for any help.
Edit:
In fact, The issue is not specific for MVVM, but for any async event handler.
For example:
// class with some logic, can be UI or whatever.
public class MyClassA
{
Size size;
public Size Size
{
get { return size; }
set
{
size = value;
SizeChanged?.Invoke(this, EventArgs.Empty);
}
}
public event EventHandler SizeChanged;
}
// this class uses the MyClassA class.
public class MyCunsomerClass
{
readonly MyClassA myClassA = new MyClassA();
public MyCunsomerClass()
{
myClassA.SizeChanged += MyClassA_SizeChanged;
}
public string Status { get; private set; } = "BEFORE";
private async void MyClassA_SizeChanged(object sender, EventArgs e)
{
await LongRunningTaskAsync();
Status = "AFTER";
}
public async Task LongRunningTaskAsync()
{
await Task.Delay(3000);
///await XYZ....;
}
public void SetSize()
{
myClassA.Size = new Size(20, 30);
}
}
Now, I want to test it:
[TestMethod]
public void TestMyClass()
{
var cunsomerClass = new MyCunsomerClass();
cunsomerClass.SetSize();
Assert.AreEqual(cunsomerClass.Status, "AFTER");
}
The test failed.
I asked Stehphen Cleary [The famous professor of asynchronous], and he answered me:
If by "async event handler" you mean an async void event handler,
then no, those aren't testable. However, they are often useful in a UI
application. So what I usually end up doing is having all my async
void methods be exactly one line long. They all look like this:
async void SomeEventHandler(object sender, EventArgsOrWhatever args)
{
await SomeEventHandlerAsync(sender, args);
}
async Task SomeEventHandlerAsync(object sender, EventArgsOrWhatever args)
{
... // Actual handling logic
}
Then the async Task version is unit testable, composable, etc. The
async void handler isn't, but that's acceptable since it no longer
has any real logic at all.
Thanks Stephen! Your idea is excellent!
Ok So first of all, I would move the worker out to an other class and make an interface to it. So that when I run the test I can inject another worker!
public class MyViewModel : BindableBase
{
private IWorker _worker;
private readonly DataHolder _data = new DataHolder(){Test = DataHolder.BeforeKey};
public string Status { get { return _data.Status; } }
public MyViewModel(IWorker worker = null)
{
_worker = worker;
if (_worker == null)
{
_worker = new Worker();
}
this.PropertyChanged += MyViewModel_PropertyChanged;
}
private void MyViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
Action action = async () => await _worker.DoSomething(_data);
action();
}
string bindagleProp;
public string BindagleProp
{
get { return bindagleProp; }
set { SetProperty(ref bindagleProp, value); }
}
}
public class DataHolder
{
public const string BeforeKey = "before";
public const string AfterKey = "After";
public string Status;
}
public interface IWorker
{
Task DoSomething(DataHolder data);
}
public class Worker : IWorker
{
public async Task DoSomething(DataHolder data)
{
await Task.Delay(3000);
data.Status = DataHolder.AfterKey;
}
}
Now the inject code would look something like:
[TestMethod]
public async Task TestMyViewModel()
{
TestWorker w = new TestWorker();
MyViewModel viewModel = new MyViewModel(w);
Assert.AreEqual(viewModel.Status, DataHolder.BeforeKey, "before check");
viewModel.BindagleProp = "abc";
Assert.AreEqual(viewModel.Status, DataHolder.AfterKey, "after check");
}
public class TestWorker : IWorker
{
public Task DoSomething(DataHolder data)
{
data.Status = DataHolder.BeforeKey;
return null; //you maybe should return something else here...
}
}
I've got an app that has to do the following type of things, preferably on the GUI thread since that's where most of the action is taking place and there's no long-running ops:
Wait 1000
FuncA()
Wait 2000
FuncB()
Wait 1000
FuncC()
I realize I could use a timer with a state-machine style OnTick function, but that seems cumbersome:
int _state;
void OnTick(object sender, EventArgs e) {
switch (_state) {
case 0:
FuncA();
_timer.Interval = TimeSpan.FromSeconds(2);
_state = 1;
break;
case 1:
FuncB();
_timer.Interval = TimeSpan.FromSeconds(1);
_state = 2;
break;
case 2:
FuncC();
_timer.IsEnabled = false;
_state = 0;
}
}
Plus I'd like to be able to make it generic enough to do something like
RunSequenceOnGuiThread(new Sequence {
{1000, FuncA}
{2000, FuncB}
{1000, FuncC}};
Is there an idiomatic way to do this kind of thing? Given all the TPL stuff, or Rx, or even the computation expressions in F# I'd assume one exists, but I'm not finding it.
Observable.Concat(
Observer.Timer(1000).Select(_ => Func1()),
Observer.Timer(2000).Select(_ => Func2()),
Observer.Timer(1000).Select(_ => Func3()))
.Repeat()
.Subscribe();
The only thing you have to do to make this work, is make sure that your Func's return a value (even if that value is Unit.Default, i.e. nothing)
Edit: Here's how to make a generic version:
IObservable<Unit> CreateRepeatingTimerSequence(IEnumerable<Tuple<int, Func<Unit>>> actions)
{
return Observable.Concat(
actions.Select(x =>
Observable.Timer(x.Item1).Select(_ => x.Item2())))
.Repeat();
}
Here's a sketch of this in F#:
let f() = printfn "f"
let g() = printfn "g"
let h() = printfn "h"
let ops = [
1000, f
2000, g
1000, h
]
let runOps ops =
async {
for time, op in ops do
do! Async.Sleep(time)
op()
} |> Async.StartImmediate
runOps ops
System.Console.ReadKey() |> ignore
That's in a console app, but you can just call runOps on the GUI thread. See also this blog.
If you're using VS11/NetFx45/C#5, you can do a similar thing with C# async/await and a List of Tuple of Action delegates.
using the async CTP or .NET 4.5 (C# 5) it's REALLY easy using an async method and the await operator. This can be called directly on the UI thread and it will work as expected.
public async void ExecuteStuff()
{
await TaskEx.Delay(1000);
FuncA();
await TaskEx.Delay(2000);
FuncB();
await TaskEx.Delay(1000);
FuncC();
}
Here's a way to combine "yield return" and the reactive framework to give you a "poor man's async". Basically lets you "await" any IObservable. Here I just use it for timers since that's what you were interested in, but it you can have it "await" button clicks (using a Subject<Unit>) etc before moving on to the next thing as well.
public sealed partial class Form1 : Form {
readonly Executor _executor = new Executor();
public Form1() {
InitializeComponent();
_executor.Run(CreateAsyncHandler());
}
IEnumerable<IObservable<Unit>> CreateAsyncHandler() {
while (true) {
var i = 0;
Text = (++i).ToString();
yield return WaitTimer(500);
Text = (++i).ToString();
yield return WaitTimer(500);
Text = (++i).ToString();
yield return WaitTimer(500);
Text = (++i).ToString();
}
}
IObservable<Unit> WaitTimer(double ms) {
return Observable.Timer(TimeSpan.FromMilliseconds(ms), new ControlScheduler(this)).Select(_ => Unit.Default);
}
}
public sealed class Executor {
IEnumerator<IObservable<Unit>> _observables;
IDisposable _subscription = new NullDisposable();
public void Run(IEnumerable<IObservable<Unit>> actions) {
_observables = (actions ?? new IObservable<Unit>[0]).Concat(new[] {Observable.Never<Unit>()}).GetEnumerator();
Continue();
}
void Continue() {
_subscription.Dispose();
_observables.MoveNext();
_subscription = _observables.Current.Subscribe(_ => Continue());
}
public void Stop() {
Run(null);
}
}
sealed class NullDisposable : IDisposable {
public void Dispose() {}
}
It's a slight modification of Daniel Earwicker's AsyncIOPipe idea: http://smellegantcode.wordpress.com/2008/12/05/asynchronous-sockets-with-yield-return-of-lambdas/
Interesting all the different responses. Here's a simple DIY option that doesn't depend on any other libraries, and doesn't hog thread resources unnecessarily.
Basically, for each action in your list, it creates an onTick function that executes that action, then recursively calls DoThings with the remaining actions and delays.
Here, ITimer is just a simple wrapper around DispatcherTimer (but it would work with a SWF Timer as well, or a mock timer for unit testing), and DelayedAction is just a Tuple with int Delay and Action action
public static class TimerEx {
public static void DoThings(this ITimer timer, IEnumerable<DelayedAction> actions) {
timer.DoThings(actions.GetEnumerator());
}
static void DoThings(this ITimer timer, IEnumerator<DelayedAction> actions) {
if (!actions.MoveNext())
return;
var first = actions.Current;
Action onTick = null;
onTick = () => {
timer.IsEnabled = false;
first.Action();
// ReSharper disable AccessToModifiedClosure
timer.Tick -= onTick;
// ReSharper restore AccessToModifiedClosure
onTick = null;
timer.DoThings(actions);
};
timer.Tick += onTick;
timer.Interval = first.Delay;
timer.IsEnabled = true;
}
}
If you don't want to delve into F# or reference Rx or use .Net 4.5 this is a simple viable solution.
Here's an example of how to test it:
[TestClass]
public sealed class TimerExTest {
[TestMethod]
public void Delayed_actions_should_be_scheduled_correctly() {
var timer = new MockTimer();
var i = 0;
var action = new DelayedAction(0, () => ++i);
timer.DoThings(new[] {action, action});
Assert.AreEqual(0, i);
timer.OnTick();
Assert.AreEqual(1, i);
timer.OnTick();
Assert.AreEqual(2, i);
timer.OnTick();
Assert.AreEqual(2, i);
}
}
And here's the other classes to make it compile:
public interface ITimer {
bool IsEnabled { set; }
double Interval { set; }
event Action Tick;
}
public sealed class Timer : ITimer {
readonly DispatcherTimer _timer;
public Timer() {
_timer = new DispatcherTimer();
_timer.Tick += (sender, e) => OnTick();
}
public double Interval {
set { _timer.Interval = TimeSpan.FromMilliseconds(value); }
}
public event Action Tick;
public bool IsEnabled {
set { _timer.IsEnabled = value; }
}
void OnTick() {
var handler = Tick;
if (handler != null) {
handler();
}
}
}
public sealed class MockTimer : ITimer {
public event Action Tick;
public bool IsEnabled { private get; set; }
public double Interval { set { } }
public void OnTick() {
if (IsEnabled) {
var handler = Tick;
if (handler != null) {
handler();
}
}
}
}
public sealed class DelayedAction {
readonly Action _action;
readonly int _delay;
public DelayedAction(int delay, Action action) {
_delay = delay;
_action = action;
}
public Action Action {
get { return _action; }
}
public int Delay {
get { return _delay; }
}
}
If you can use the C# 4.5 to do it, go with Firoso post: it's the best way accomplish that in C#, exactly what Async was built for.
However, if you can't, there might be some ways to do it. I'd do a "simple" manager to do it:
public partial class Form1 : Form
{
private TimedEventsManager _timedEventsManager;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
_timedEventsManager
= new TimedEventsManager(this,
new TimedEvent(1000, () => textBox1.Text += "First\n"),
new TimedEvent(5000, () => textBox1.Text += "Second\n"),
new TimedEvent(2000, () => textBox1.Text += "Third\n")
);
}
private void button1_Click(object sender, EventArgs e)
{
_timedEventsManager.Start();
}
}
public class TimedEvent
{
public int Interval { get; set; }
public Action Action { get; set; }
public TimedEvent(int interval, Action func)
{
Interval = interval;
Action = func;
}
}
public class TimedEventsManager
{
private readonly Control _control;
private readonly Action _chain;
public TimedEventsManager(Control control, params TimedEvent[] timedEvents)
{
_control = control;
Action current = null;
// Create a method chain, beginning by the last and attaching it
// the previous.
for (var i = timedEvents.Length - 1; i >= 0; i--)
{
var i1 = i;
var next = current;
current = () =>
{
Thread.Sleep(timedEvents[i1].Interval);
// MUST run it on the UI thread!
_control.Invoke(new Action(() => timedEvents[i1].Action()));
if (next != null) next();
};
}
_chain = current;
}
public void Start()
{
new Thread(new ThreadStart(_chain)).Start();
}
}
Beware that this example is Winforms specific (uses Control.Invoke()). You will need a slightly different version for WPF, which uses the thread dispatcher to achieve the same thing. (if my memory doesn't fail me, you also can use Control.Dispatcher.Invoke(), but keep in mind that it is a different control)
I have this sample code for async operations (copied from the interwebs)
public class LongRunningTask
{
public LongRunningTask()
{
//do nowt
}
public int FetchInt()
{
Thread.Sleep(2000);
return 5;
}
}
public delegate TOutput SomeMethod<TOutput>();
public class GoodPerformance
{
public void BeginFetchInt()
{
LongRunningTask lr = new LongRunningTask();
SomeMethod<int> method = new SomeMethod<int>(lr.FetchInt);
// method is state object used to transfer result
//of long running operation
method.BeginInvoke(EndFetchInt, method);
}
public void EndFetchInt(IAsyncResult result)
{
SomeMethod<int> method = result.AsyncState as SomeMethod<int>;
Value = method.EndInvoke(result);
}
public int Value { get; set; }
}
Other async approaches I tried required the aysnc page attribute, they also seemed to cancel if other page elements where actioned on (a button clicked), this approach just seemed to work.
I’d like to add a cancel ability and exception handling for the longRunningTask class, but don’t erm, really know how.
In example:
public class ValueEventArgs : EventArgs
{
public int Value { get;set;}
}
public class ExceptionEventArgs : EventArgs
{
public Exception Exception { get;set;}
}
public class LongRunningTask
{
private bool canceled = false;
public event EventHandler<ValueEventArgs> Completed = delegate {}
public event EventHandler<ExceptionEventArgs> GotError = delegate {}
public void Cancel()
{
canceled = true;
}
public void FetchInt()
{
try
{
int result = 0;
for (int i = 0; i < 1000; i++)
{
if (canceled)
return;
result++;
}
Completed(this, new ValueEventArgs {Value = result});
}
catch(Exception exc)
{
GotError(this, new ExceptionEventArgs { Exception = exc });
}
}
public void BeginFetchInt()
{
ThreadPool.QueueUserWorkItem(i => FetchInt());
}
}
And somewhere:
LongRunningTask task = new LongRunningTask();
task.Completed +=new EventHandler<ValueEventArgs>(task_Completed);
task.GotError +=new EventHandler<ExceptionEventArgs>(task_GorError);
task.BeginFetchInt();
//in any moment until it calculates you may call:
task.Cancel();