How can I turn the below method into the right format for returning a task items. The method stub requires a task to be used. This is my first time into async methods I am using it for the windows phone 8 like below:
private System.Threading.Tasks.Task listView_PullToRefreshRequested(object sender, EventArgs e)
{
Populatelist();
}
public async void Populatelist()
{
try
{
curoListsDal _db = new curoListsDal();
cLists = await _db.GetListsAync();
listView.ItemsSource = cLists;
}
catch (Exception ex)
{
}
}
The right format would be to return a Task instead of void in PopulateListAsync and await on that inside your event handler:
private async void PullToRefreshRequestAsync(object sender, EventArgs e)
{
await PopulateListAsync();
}
public async Task PopulateListAsync()
{
curoListsDal db = new curoListsDal();
listView.ItemsSource = await db.GetListsAsync();
}
Side note: don't swallow exceptions.
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
}
It is necessary to execute the methods sequentially in the order they were started, but without stopping the UI. In the example that I made, the operations are performed asynchronously, which leads to incorrect entries in the ListNumber list.
public Form1()
{
InitializeComponent();
ListNumber = new List<string>();
}
List<string> ListNumber { get; set; }
private async void button1_Click(object sender, EventArgs e)
{
textBox1.Text = await Task.Run(() => MessageAsync());
}
private async Task<string> MessageAsync()
{
var concat = "";
await NumberAsync();
foreach (string number in ListNumber)
{
concat += number + ", ";
}
return concat;
}
private async Task NumberAsync()
{
for(int i = 0; i < 30; i++)
{
ListNumber.Add(i.ToString());
await Task.Delay(300);
}
}
If you quickly click on the button, the calling method gives the following result:
the result of the program
Xerillio's proposed solution does work as long as you don't expect the button to be responsive after be pressed:
private async void button1_Click(object sender, EventArgs e)
{
button1.IsEnabled = false;
textBox1.Text = await Task.Run(() => MessageAsync());
button1.IsEnabled = true;
}
If you need to be able to use the button while your task is running, or in other words you expect several things to need access to the ListNumber resource you need to design a system for controlling access to that resource. Only allowing one producer to add values to the list at a time for instance would be a method but it all depends on what behavior you want to see.
Below is a working version which controls access to the LisNumber object using a semaphore.
public MainWindow()
{
InitializeComponent();
ListNumber = new List<string>();
semaphore = new SemaphoreSlim(1, 1);
}
SemaphoreSlim semaphore;
List<string> ListNumber { get; set; }
private async void button1_Click(object sender, EventArgs e)
{
await NumberAsync();
textBox1.Text = await Message();
}
private async Task<string> Message()
{
await semaphore.WaitAsync();
var concat = "";
foreach (string number in ListNumber)
{
concat += number + ", ";
}
semaphore.Release();
return concat;
}
private async Task NumberAsync()
{
await semaphore.WaitAsync();
for (int i = 0; i < 30; i++)
{
ListNumber.Add(i.ToString());
await Task.Delay(300);
}
semaphore.Release();
}
You could also just wrap the button call in the semaphore if you wanted:
private async void button1_Click(object sender, EventArgs e)
{
await semaphore.WaitAsync();
await NumberAsync();
textBox1.Text = await Message();
semaphore.Release();
}
static async void SendTweetWithSinglePicture(string message, string image)
{
var auth = new SingleUserAuthorizer
{
CredentialStore = new SingleUserInMemoryCredentialStore
{
ConsumerKey = "",
ConsumerSecret = "",
AccessToken = "",
AccessTokenSecret = ""
}
};
var context = new TwitterContext(auth);
var uploadedMedia = await context.UploadMediaAsync(File.ReadAllBytes(#image));
var mediaIds = new List<ulong> { uploadedMedia.MediaID };
await context.TweetAsync(
message,
mediaIds
);
}
protected void Page_Load(object sender, EventArgs e)
{
SendTweetWithSinglePicture("test", "path");
}
How can I call a async method on Page_Load?
The question is if you want to make the Page_Load method async or not. If so:
protected async void Page_Load(object sender, EventArgs e)
{
await SendTweetWithSinglePicture("test", "path");
}
Or if you don't want it to be async:
protected void Page_Load(object sender, EventArgs e)
{
SendTweetWithSinglePicture("test", "path").Wait();
}
This does require your async method to return Task as it always should! (except event handlers)
The problem with this might be that the method doesn't complete before rendering the page. If it has to, you'd better make the method synchronous, or register the task using Page.RegisterAsyncTask and Page.ExecuteRegisteredAsyncTasks. Effectively this will freeze the Page_Load method too.
protected void Page_Load(object sender, EventArgs e)
{
PageAsyncTask t = new PageAsyncTask(SendTweetWithSinglePicture("test", "path"));
// Register the asynchronous task.
Page.RegisterAsyncTask(t);
// Execute the register asynchronous task.
Page.ExecuteRegisteredAsyncTasks();
}
You should use PageAsyncTask. It has samples in MSDN page.
// Register the asynchronous task.
Page.RegisterAsyncTask(new PageAsyncTask(SendTweetWithSinglePicture(message, image));
// Execute the register asynchronous task.
Page.ExecuteRegisteredAsyncTasks();
as I pointed the sample and explanations on MSDN page is pretty good.
Try This :
public void Page_Load(object sender, EventArgs e)
{
RegisterAsyncTask(new PageAsyncTask(LoadSomeData));
}
public async Task LoadSomeData()
{
var clientcontacts = Client.DownloadStringTaskAsync("api/contacts");
var clienttemperature = Client.DownloadStringTaskAsync("api/temperature");
var clientlocation = Client.DownloadStringTaskAsync("api/location");
await Task.WhenAll(clientcontacts, clienttemperature, clientlocation);
var contacts = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Contact>>(await clientcontacts);
var location = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(await clientlocation);
var temperature = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(await clienttemperature);
listcontacts.DataSource = contacts;
listcontacts.DataBind();
Temparature.Text = temperature;
Location.Text = location;
}
This question already has answers here:
Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on
(22 answers)
Closed 3 years ago.
I'm trying to load data to a combobox and it's working when i run the form without debugging. But when i try to run it with debug mode I get an error :System.InvalidOperationException: 'Cross-thread operation not valid: Control 'ResultBox' accessed from a thread other than the thread it was created on.'
How can I fix this? And btw a have a background worker that writes the message when the data is downloaded. I read somewhere that this issue can be fixed using backgroundworker. Here is the form code:
public Form1()
{
InitializeComponent();
backgroundWorker1.WorkerReportsProgress = true;
}
private void Form1_Load(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private Task GetDataTask() {
return Task.Factory.StartNew(() => {
List<Result> results = new List<Result>();
results =
GetResults.GetData("http://worldcup.sfg.io/teams/results/");
foreach (var result in results)
{
ResultBox.Items.Add(result.Fifa_Code);
}
});
}
private void ResultBox_SelectedIndexChanged(object sender, EventArgs e)
{
}
private void SaveTeam_Click(object sender, EventArgs e)
{
}
private async void backgroundWorker1_DoWork(object sender,
DoWorkEventArgs e)
{
await GetDataTask();
}
private void backgroundWorker1_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
resultsLoadedLabel.Text = (e.ProgressPercentage.ToString() + "%");
}
private void backgroundWorker1_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
resultsLoadedLabel.Text = "Podaci učitani!";
}
This line of code inside foreach gets the exception :
ResultBox.Items.Add(result.Fifa_Code);
This is the class that gets results:
public class GetResults
{
public static List<Result> GetData(string url) {
var client = new RestClient();
var request = new RestRequest(url, Method.GET);
request.AddHeader("User-Agent", "Nothing");
IRestResponse<List<Result>> results = client.Execute<List<Result>>
(request);
return results.Data;
}
}
If going async, then go async all the way. RestSharp allows you to make async calls
So you can refactor data access to
public class GetResults {
public static async Task<List<Result>> GetDataAsync(string url) {
var client = new RestClient();
var request = new RestRequest(url, Method.GET);
request.AddHeader("User-Agent", "Nothing");
IRestResponse<List<Result>> results = await client.ExecuteTaskAsync<List<Result>>(request);
return results.Data;
}
}
Next, since the form load is an event handler, you can make that async as well and load the data.
public Form1() {
InitializeComponent();
}
private async void Form1_Load(object sender, EventArgs e) {
//On UI thread
resultsLoadedLabel.Text = "Loading data!";
//get data on separate thread (non blocking)
List<Result> results = await GetResults.GetDataAsync("http://worldcup.sfg.io/teams/results/");
//Back on UI thread
resultsLoadedLabel.Text = "Podaci učitani!";
foreach (var result in results) {
ResultBox.Items.Add(result.Fifa_Code);
}
}
Making sure when accessing UI controls while using async calls that they are accessed on the main thread that created them (see comments).
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.