Is there a way to make an asynchronous call to a custom method in WP7 - WP8?
In a Windows Forms app i would simply do this:
private void btnStart_Click(object sender, EventArgs e)
{
MyMethod();
}
private async void MyMethod()
{
await System.Threading.Tasks.Task.Run(() => Thread.Sleep(5000));
}
However, it seems like the System.Threading.Tasks namespace is not supported in WP apps.
Then what should i do if i wished to act similarly in my WP7 - WP8 app?
You can install Microsoft.Bcl.Async for WP7.5 support. If you need WP7.0 support, your best bet is BackgroundWorker.
P.S. Your WinForms example would be better written as:
private async void btnStart_Click(object sender, EventArgs e)
{
await Task.Run(() => MyMethod());
}
private void MyMethod()
{
Thread.Sleep(5000);
}
Following these best practices:
Avoid async void.
Don't use Task.Run in general-purpose library methods.
Related
so I am making a small WPF app.
I am new to C# and Multithreading, I want to run certain methods in sequence but because one of the methods is Async it does not run in sequence.
private async void LoadButton_Click(object sender, RoutedEventArgs e)
{
if (!OpenFile()) return; // opens a file dialog and ensure format is correct
await Task.Run(() =>
{
// some heavy task which I run here so that I dont freeze the UI
});
}
private void TheFunctionIwantToRunInSeqeuence(object sender, RoutedEventArgs e)
{
LoadButton_Click(sender, e);
SaveCareerInfoButton_Click(sender, e); // I want this line to wait for load to finish
LoadButton_Click(sender, e);
ImportCareerInfoButton_Click(sender, e); // I want this line to wait for the second load to finish
}
Await these calls as well, refactor your code a bit.. extract handler's content to a separate method and don't pass senders and args between handlers
private Task Load()
{
if (!OpenFile()) return;
return Task.Run(() =>
{
// some heavy task which I run here so that I dont freeze the UI
});
}
private async void LoadButton_Click(object sender, RoutedEventArgs e)
{
await Load();
}
private async void TheFunctionIwantToRunInSeqeuence(object sender, RoutedEventArgs e)
{
await Load();
// refactor your code to not pass sender, e.. SaveCareer();
SaveCareerInfoButton_Click(sender, e);
await Load();
// refactor your code to not pass sender, e.. ImportCareer();
ImportCareerInfoButton_Click(sender, e);
}
You can use await to wait an async function to finish and make function TheFunctionIwantToRunInSeqeuence to async Task return type:
private async Task TheFunctionIwantToRunInSeqeuence(object sender, RoutedEventArgs e)
{
await LoadButton_Click(sender, e);
SaveCareerInfoButton_Click(sender, e); // I want this line to wait for load to finish
await LoadButton_Click(sender, e);
ImportCareerInfoButton_Click(sender, e); // I want this line to wait for the second load to finish
}
I need to add an element to a Winform ListView control from other thread, so I am using a delegate, this way:
private delegate void AddMessageLogCallback(string message);
public void AddMessageLog(string message)
{
if (InvokeRequired)
Invoke(new AddMessageLogCallback(AddMessageLog), message);
else
{
lstLogs.Items.Add(message).EnsureVisible();
}
}
The problem is that the Invoke does nothing, not even throws an exception.
I have used this kind of delegates before and never had problems. What different is at this time?
Your code works as desired with the test code below, so the problem should be something else.
private void button1_Click(object sender, EventArgs e)
{
AddMessageLog("local message");
}
private async void button2_Click(object sender, EventArgs e)
{
await Task.Run(() => AddMessageLog("async message"));
}
Btw, I would mention that there is no need to define a new AddMessageLogCallback delegate and to call the AddMessageLog recursively. So a more simple (and maybe cleaner) solution:
public void AddMessageLog(string message)
{
Action addLog = () => lstLogs.Items.Add(message).EnsureVisible();
if (InvokeRequired)
Invoke(addLog);
else
addLog();
}
I have code similar to following inside my Windows form:
private async Task<string> GetGreetingAsync()
{
return await Task.Run(() => "Hello");
}
private void button1_Click(object sender, EventArgs e)
{
var x = GetGreetingAsync().Result;
}
Clicking the button causes the entire Windows form to freeze and become unresponsive. No exception is thrown.
Even when I don't use the task .Result directly in the event handler and the whole async marked code is in some class library function, which provides interface without async, the problem still occurs. Unit tests for such class library pass without any problems, but when I call its function from event handler on Windows form, it breaks and does not respond.
Why does this happen? How can I fix it?
You are blocking the the UI thread with .Result; (see ConfigureAwait)
private async Task<string> GetGreetingAsync()
{
return await Task.Run(() => "Hello").ConfigureAwait(false);
}
private void button1_Click(object sender, EventArgs e)
{
var x = GetGreetingAsync().Result;
}
Or go all the way async
private async Task<string> GetGreetingAsync()
{
return await Task.Run(() => "Hello");
}
async private void button1_Click(object sender, EventArgs e)
{
var x = await GetGreetingAsync();
}
Using this version you don't even need to await in GetGreetingAsync
private Task<string> GetGreetingAsync()
{
return Task.Run(() => "Hello");
}
async private void button1_Click(object sender, EventArgs e)
{
var x = await GetGreetingAsync();
}
You should be using await instead of Result on a Task<T> to get non-blocking behavior.
private async void button1_Click(object sender, EventArgs e)
{
var x = await GetGreetingAsync();
}
Calling Result causes the code to wait until the Task has completed where calling await allows the async behavior to be used.
Edit
Actually looking at your code again if you're doing
private async Task<string> GetGreetingAsync()
{
return await new Task<string>(() => "Hello");
}
That is really not needed. That block can just be
private Task<string> GetGreetingAsync()
{
return new Task<string>(() => "Hello");
}
There's no need for the thing returning the task to be async.
I was wondering how i could make this method async, it gives me an error: The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'.
Here's my code:
void OnRegister(object sender, RoutedEventArgs e)
{
await PrintManager.ShowPrintUIAsync();
}
You're welcome:
async void OnRegister(object sender, RoutedEventArgs e)
{
await PrintManager.ShowPrintUIAsync();
}
You can't use await without a async method(this would not make any sense).
async Task<int> OnRegisterAsync(object sender, RoutedEventArgs e)
{
await PrintManager.ShowPrintUIAsync();
return 0;
}
You need to decorate the method which contains 'await' with 'async'.
In your case I'm guessing you can't make OnRegister return a Task so you'll need a helper method. Something like this should work:
void OnRegister(object sender, RoutedEventArgs e)
{
RegisterAsync();
}
async void RegisterAsync() {
await PrintManager.ShowPrintUIAsync();
}
Notice how the RegisterAsync method is decorated with 'async' and returns a Task. Which in turn needs to be started by the caller.
Reference: http://msdn.microsoft.com/en-us/library/hh191443.aspx
I'm just creating a ContextMenu..
At this line, I don't know what I shall put in the third param (or better: how I have to form it -syntaxly-):
(contextMenuStrip.Items[0] as System.Windows.Forms.ToolStripMenuItem).DropDownItems.Add(contextUnterMenuStrip.Items.Add(exe),null, HERE);
on 'HERE' I have to set an EventHandler onClick
By Example I got this Method:
public void DoSomething()
{
//...
}
How could I call this Method? (Over the Eventhandler?) or do I have to make a Method like:
private void button_Click(object sender, RoutedEventArgs e)
{
//...
}
Don't "call" the method but take its address. Which means omitting the ()
private void menuItem1_Click(object sender, EventArgs e)
{
//...
}
// your code, I think it misses a few ')'
... (contextMenuStrip.Items[0] as System.Windows.Forms.ToolStripMenuItem)
.DropDownItems.Add(contextUnterMenuStrip.Items
.Add(exe),null, menuItem1_Click);
As you can see here, the callback has to have the following prototype:
public delegate void EventHandler( Object sender, EventArgs e )
So your method DoSomething has to look like:
private void DoSomething(object sender, EventArgs e)
{
//...
}
You can create an anonymous event handler using the Linq libraries and call your method that way. This can be a nice and quick way of doing something (especially if it's just a test project). But if you start using it extensively, it might become difficult to read it.
An example of this would be:
var menuItem1 = new MenuItem();
menuItem1.Click += (sender, e) => DoSomething();
Refer here for further information on using Linq: http://msdn.microsoft.com/library/bb308959.aspx