C# async await not working winforms ui freeze - c#

How to use _Asyn methods correctly ?
With my limited experience with C#, I don't know why. How to improve it? Thanks in advance.
//use :
this.SyncDataDataGridView.DataSource = await patentLaunch.LoadAccessDbListAsync();
//Method-01 winfroms UI OK (use ToList() )
public async Task<List<SyncNotice>> LoadAccessDbListAsync01()
{
return await Task.Run(() =>
{
using (var context = new SyncDbContextContext())
{
return context.SyncNotices.OrderByDescending(m => m.Id).Take(1000).ToList();
}
});
}
//Method-02 winfroms UI freeze ! ( use ToListAsync() EntityFrameworkCore )
public Task<List<SyncNotice>> LoadAccessDbListAsync02()
{
using (var context = new SyncDbContextContext())
{
return context.SyncNotices.OrderByDescending(m => m.Id).Take(1000).ToListAsync();
}
}
my full code is:
private async void Form_Load(object sender, EventArgs e){
//init binding
await context.SyncNotices.LoadAsync();
this.SyncDataDataGridView.DataSource = context.SyncNotices.Local.ToBindingList();
}
//init event
patentLaunch.OnFolderAddAccessOk += () => {
Invoke(new Action(async () =>
{
this.SyncDataDataGridView.DataSource = await patentLaunch.LoadAccessDbListAsync02();
}));
};
};
}
//call in fileSystemWatcher1_Created(object sender, System.IO.FileSystemEventArgs e)
//in patentLaunch.cs
public void AddSigleFloderToAccessDb(string folder, string syncStatus)
{
var now = DateTime.Now;
var entity = new SyncNotice
{
FolderName = folder,
CreateTime = now,
SyncStatus = syncStatus
};
using (var context = new SyncDbContextContext())
{
context.SyncNotices.Add(entity);
context.SaveChanges();
}
UpdateLastExecTime(now);
// send event
OnFolderAddAccessOk();
}
//in patentLaunch.cs
public event Action OnFolderAddAccessOk;
Thanks for JonasH . Thank you for your reply.
,finally I used mehtod01
Some databases do not support truly async queries. In that case queries may be synchronous even if there is a *Async-method.
I have not found any concrete documentation about access supporting or not supporting asynchronous queries. But based on its age, and the fact that your call is actually blocking, I would guess the chances are low.
So as far as I know you just have to use LoadAccessDbListAsync01 to avoid blocking.

Some databases do not support truly async queries. In that case queries may be synchronous even if there is a *Async-method.
I have not found any concrete documentation about access supporting or not supporting asynchronous queries. But based on its age, and the fact that your call is actually blocking, I would guess the chances are low.
So as far as I know you just have to use LoadAccessDbListAsync01 to avoid blocking.

Related

Run async/await method on other than UI thread [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I have a WPF app with an EF connection to a database. But when I call await DbSet().SingleAsync() my UI thread is stuck and not responsive. I figured out that when I ran await it will still run on main UI thread so I can access UI. That will explain why it is working when I use only Task.Delay(), because SingleAsync is using thread, but Task.Delay() doesn't.
ConfigureAwait(false) should solve this and run it on different thread. But it doesn't and my UI still freeze.
Am I doing it wrong ?
Code:
private async void Button_Login_Click(object sender, RoutedEventArgs e)
{
await userService.ValidateCredentials(textBoxLogin.Text, textBoxLogin.Text).ConfigureAwait(false);
}
public async Task<bool> ValidateCredentials(string username, string password)
{
User user = await userDao.SingleOrNull(true, o => o.Username == username && o.Password == password);
if (user == null)
return (false);
return (true);
}
public async Task<ResourceDbType> SingleOrNull(bool noTracking, Expression<Func<ResourceDbType, bool>> where)
{
ResourceDbType ret;
try
{
if (noTracking)
{
ret = await GetDbSet().AsNoTracking().SingleAsync(where);
}
else
ret = await GetDbSet().SingleAsync(where);
}
catch (Exception ex)
{
return null;
}
return ret;
}
EDIT:
BaseDao should only expose functions from DbContext with selected DbSet model registered at MainDbContext. We are using this code at work at RestApi service, so I reused it because I am used to it.
[RegisterClass(Lifetime.Scoped)] is atribute for marking class to Register it in DependencyInjection at start of app with reflection.
Dao code:
public class BaseDao<ResourceDbType> : IDisposable where ResourceDbType : class, new()
{
public DbContext DbContext { get; protected set; }
public BaseDao(MainDbContext mainDbContext)
{
DbContext = mainDbContext;
}
public DbSet<ResourceDbType> GetDbSet()
{
return this.DbContext.Set<ResourceDbType>();
}
public List<ResourceDbType> ToList()
{
return this.GetDbSet().ToList();
}
public ResourceDbType[] ToArray()
{
return this.GetDbSet().ToArray();
}
public async Task<ResourceDbType> SingleOrNull(bool noTracking, Expression<Func<ResourceDbType, bool>> where)
{
ResourceDbType ret;
try
{
if (noTracking)
{
ret = await GetDbSet().AsNoTracking().SingleAsync(where);
}
else
ret = await GetDbSet().SingleAsync(where);
}
catch (Exception ex)
{
return null;
}
return ret;
}
public void Dispose()
{
this.DbContext?.Dispose();
}
}
UserDao Code:
[RegisterClass(Lifetime.Scoped)]
public class UserDao : BaseDao<User>
{
public UserDao(MainDbContext mainDbContext) : base(mainDbContext)
{
}
}
Async is not a silver bullet, and from what I see from the example, it is most likely unnecessary. Async is not ideal for "use everywhere, every time" but rather for potentially mitigating expensive operations.
By tucking away EF behind a service and then a repository makes your EF operations a lot less efficient than they could be.
For example: Without a repository level. (Trust EF to be used by the service, and injected into the service)
// UI
private void Button_Login_Click(object sender, RoutedEventArgs e)
{
var result = userService.ValidateCredentials(textBoxLogin.Text, textBoxLogin.Text);
}
// Service
public bool ValidateCredentials(string username, string password)
{
var result = Context.Users.Any(x => x.UserName == userName && x.Password == password);
return result;
}
EF can generate a very efficient EXISTS query rather than loading an entity just to check if a row exists. Faster code without needing to worry about handing it off.
If you want to be able to unit test the service, then you can introduce a repository. I recommend leveraging IQueryable:
// Service
public bool ValidateCredentials(string username, string password)
{
using (var unitOfWork = UnitOfWorkFactory.Create())
{
var result = UserRepository.FindUserByName(username, password).Any();
return result;
}
}
// Repository
public IQueryable<User> FindUserByName(string userName, string password)
{
var query = Context.Users.Where(x => x.UserName == userName && x.Password == password);
return query;
}
The repository can guard access to the Entities to ensure required rules are followed etc. yet can be more easily mocked out than the DbContext. This requires consideration for scoping the DbContext in a Unit of Work to facilitate the Service to control the boundary of the DbContext and interact with the resulting entities returned by the Repository. The implementation I use for that with EF is Medhime's DbContextScope. (There are forks available for EF Core) This gives the service full control over how the entities are consumed with the repository enforcing the rules and making mocking simpler.
Side Note: Some devs don't like that the services need to be aware of EF concerns (such as legal Lambdas that EF can understand) but this is a trade off for a thinner, much more flexible Repository. (Handling additional criteria, projection, sorting, paging, etc. is a snap however a particular consumer needs.) I've seen many attempts to abstract away EF to accept criteria, sorting, projection, and paging into repository methods using Func etc. but the reality is that these are quite complex and still have to adhere to EF's rules anyways. Ultimately when you choose to use EF you need to trust it as part of your solution in order to leverage it to it's fullest.
Async is geared more towards particularly expensive operations. WPF's synchronization context essentially supports interacting with async code, but since this is going to ensure code resumes on the UI thread, there is arguably little benefit using it other than facilitating it to be able to await async methods. This is more to facilitate an event handler to work properly when calling and awaiting several async operations.
I.e.
private async void Button_Login_Click(object sender, RoutedEventArgs e)
{
var firstTask = userService.DoSomethingThatMightTake5SecondsAsync(); // Don't actually name your tasks this! :)
var secondTask = userService.DoSomethingThatMightTake5SecondsAsync();
var thirdTask = userService.DoSomethingThatMightTake5SecondsAsync();
// Do stuff that doesn't rely on those 3 tasks....
var firstResult = await firstTask;
// Do something with first task results
var secondResult = await secondTask;
// Do something with second task results
var thirdResult = await thirdTask;
// Do something with third task results
}
Synchronously, those 3 operations would take 15 seconds and whatever else needs to happen that doesn't rely on them would have to wait until they complete. Asynchronously they could complete faster, and independent code could execute while they are processing.
Though caution would be needed in the above example with EF as things like the DbContext is not thread safe so kicking off 3 async methods that result in the use of a single DbContext would result in calls to the DbContext by multiple threads. Awaiting them in turn with a UI Thread Sync context is effectively the same as sync calls, only marginally slower. (Overhead of spawning the thread pool threads and waiting for the sync context)
Using async should be situational.
Edit: Example with Async vs. Sync:
With a simple WPF form with 2 buttons and a text box (uxEntry). One button for a Synchronous event, one with an Asynchronous event. The textbox will receive focus after one of the buttons is called and you can try typing in it to see if the UI thread is responding:
private async void AsyncButton_Click(object sender, RoutedEventArgs e)
{
uxEntry.Focus();
var result = await DoSomethingAsync();
MessageBox.Show(result);
}
private void SyncButton_Click(object sender, RoutedEventArgs e)
{
uxEntry.Focus();
var result = DoSomethingSync();
MessageBox.Show(result);
}
private async Task<string> DoSomethingAsync()
{
await Task.Run(() =>
{
Thread.Sleep(5000);
});
return "Done";
}
private string DoSomethingSync()
{
Thread.Sleep(5000);
return "Done";
}
In the case where you click the Sync button, the text box won't receive focus or accept input until the 5 seconds is up. In the Async example, it will respond immediately while the async task is running. Async events allow the UI thread to continue responding to events which can make your app feel more responsive, however combining this with EF DbContexts, which are not thread safe, can lead to issues.
Using Async to parallelize operations would be dangerous with code using a single injected DbContext reference, for example:
private async void AsyncMultiButton_Click(object sender, RoutedEventArgs e)
{
uxEntry.Focus();
var task1 = DoSomethingAsync();
var task2 = DoSomethingAsync();
var task3 = DoSomethingAsync();
var result1 = await task1;
var result2 = await task2;
var result3 = await task3;
var message = string.Format("Task1: {0} Task2: {1} Task3: {2}", result1, result2, result3);
MessageBox.Show(message);
}
If DoSomethingAsync talked to a repository DbContext those 3 tasks would all start simultaneously, and the DbContext will not like that. Depending on the code it can lead to headaches as it appears to work sometimes or in debug environments only to crash with errors at others or in production. The solution would be to await each one in turn:
uxEntry.Focus();
var result1 = await DoSomethingAsync();
var result2 = await DoSomethingAsync();
var result3 = await DoSomethingAsync();
This would be safe for the DbContext, and the UI would be responsive, however that would now take 15 seconds to complete. It can be tempting to kick them off in parallel, just something to be cautious of when using async. It can be useful for making your application appear more responsive, but be cautious when thinking it can make your application "faster".
Looking at your original code example I don't see a glaring reason why the awaited event handler would still appear to lock up the UI, though that may be some difference between your current code and the example you provided.

Task.Run() in C# doesn't execute some parts

I want to do a task in background without freezing the main User Interface. However, I have some problem using Task.Run() with anonymous function in C# because it seems like it doesn't execute the code. I think my implementation may be incorrect.
private List<string> GetPdfList
{
get
{
return File.Directory.GetFiles(PDF_FILE_DIRECTORY);
}
}
private void InitializePdf()
{
if (GetPdfList.Count > 0)
{
foreach (var pdf in GetPdfList)
{
var converter = new PdfConvertor();
var format = ImageFormat.Png;
converter.Convert(pdf, TempFolder, format);
}
}
}
public MainForm()
{
InitializeComponent();
Task.Run(() =>
{
InitializePdf();
});
}
I think the problem is in foreach scope
Task.Run() creates the task, but doesn't execute it.
In order to do what you want, you should await for the task result in an async event.
See Async loading for winforms

ASP.NET - async programming

I am trying to understand async programming, and I had a question. It is regarding the following functions below.
public async void TestAsyncCall() {
Task<string> TaskResult1 = DoSomethingAsync();
string Result2 = DoSomething();
string Result1 = await TaskResult1;
}
public string DoSomething() {
return "synch";
}
public async Task<string> DoSomethingAsync() {
await Task.Delay(10000);
return "asynch";
}
In the function call TestAsyncCall(), would one thread be used to execute DoSomethingAsync(), and another thread to execute DoSomething()?
Then when await is encountered, it would wait for DoSomethingAsync() to complete and release that thread (while also not blocking the original thread)?
Or will this not warrant any new threads being created? In that case will the DoSomethingAsync call be relevant only if it were to deal with some external resource?
I recommend you read my article on async ASP.NET.
Or will this not warrant any new threads being created?
This won't create any new threads. In particular, async and await by themselves won't create any new threads.
On ASP.NET, it's likely that the code after an await will run on a different thread than the code before that await. This is just exchanging one thread for another, though; no new threads are created.
In that case will the DoSomethingAsync call be relevant only if it were to deal with some external resource?
The primary use case for async is to deal with I/O, yes. This is particularly true on ASP.NET.
As #Stepehen-cleary said, "In particular, async and await by themselves won't create any new threads."
This next example is taken from the book: "C sharp in Depth" by John Skeet, chapter 15 pp.465:
class AsyncForm : Form
{
/* The first part of listing 15.1 simply creates the UI and hooks up an event handler for
the button in a straightforward way */
Label label;
Button button;
public AsyncForm()
{
label = new Label {
Location = new Point(10, 20),
Text = "Length"
};
button = new Button {
Location = new Point(10, 50),
Text = "Click"
};
button.Click += DisplayWebSiteLength;
AutoSize = true;
Controls.Add(label);
Controls.Add(button);
}
/* When you click on the button, the text of the book’s home page is fetched
and the label is updated to display the HTML lenght in characters */
async void DisplayWebSiteLength(object sender, EventArgs e)
{
label.Text = "Fetching...";
using (HttpClient client = new HttpClient())
{
string text =
await client.GetStringAsync("http://csharpindepth.com");
label.Text = text.Length.ToString();
}
}
/* The label is updated to display the HTML length in characters D. The
HttpClient is also disposed appropriately, whether the operation succeeds or fails—
something that would be all too easy to forget if you were writing similar asynchronous
code in C# 4 */
}
With this in mind, let's take a look to your code, you have Result1 and Result2, there's no point in having one asynchronous task waiting for a synchronous task to be finished. I would use Parallelism so you can perform both methods but to return something like two sets of Data, performing LINQ queries at the same time.
Take a look to this short example about Parallelism with Async Tasks:
public class StudentDocs
{
//some code over here
string sResult = ProcessDocs().Result;
//If string sResult is not empty there was an error
if (!sResult.Equals(string.Empty))
throw new Exception(sResult);
//some code over there
##region Methods
public async Task<string> ProcessDocs()
{
string sResult = string.Empty;
try
{
var taskStuDocs = GetStudentDocumentsAsync(item.NroCliente);
var taskStuClasses = GetStudentSemesterClassesAsync(item.NroCliente, vencimientoParaProductos);
//We Wait for BOTH TASKS to be accomplished...
await Task.WhenAll(taskStuDocs, taskStuClasses);
//Get the IList<Class>
var docsStudent = taskStuDocs.Result;
var docsCourses = taskStuClasses.Result;
/*
You can do something with this data ... here
*/
}
catch (Exception ex)
{
sResult = ex.Message;
Loggerdb.LogInfo("ERROR:" + ex.Message);
}
}
public async Task<IList<classA>> GetStudentDocumentsAsync(long studentId)
{
return await Task.Run(() => GetStudentDocuments(studentId)).ConfigureAwait(false);
}
public async Task<IList<classB>> GetStudentSemesterCoursessAsync(long studentId)
{
return await Task.Run(() => GetStudentSemesterCourses(studentId)).ConfigureAwait(false);
}
//Performs task to bring Student Documents
public IList<ClassA> GetStudentDocuments(long studentId)
{
IList<ClassA> studentDocs = new List<ClassA>();
//Let's execute a Stored Procedured map on Entity Framework
using (ctxUniversityData oQuery = new ctxUniversityData())
{
//Since both TASKS are running at the same time we use AsParallel for performing parallels LINQ queries
foreach (var item in oQuery.GetStudentGrades(Convert.ToDecimal(studentId)).AsParallel())
{
//These are every element of IList
studentDocs.Add(new ClassA(
(int)(item.studentId ?? 0),
item.studentName,
item.studentLastName,
Convert.ToInt64(item.studentAge),
item.studentProfile,
item.studentRecord
));
}
}
return studentDocs;
}
//Performs task to bring Student Courses per Semester
public IList<ClassB> GetStudentSemesterCourses(long studentId)
{
IList<ClassB> studentCourses = new List<ClassB>();
//Let's execute a Stored Procedured map on Entity Framework
using (ctxUniversityData oQuery = new ctxUniversityData())
{
//Since both TASKS are running at the same time we use AsParallel for performing parallels LINQ queries
foreach (var item in oQuery.GetStudentCourses(Convert.ToDecimal(studentId)).AsParallel())
{
//These are every element of IList
studentCourses.Add(new ClassB(
(int)(item.studentId ?? 0),
item.studentName,
item.studentLastName,
item.carreerName,
item.semesterNumber,
Convert.ToInt64(item.Year),
item.course ,
item.professorName
));
}
}
return studentCourses;
}
#endregion
}

Task async and continuewith

I'm trying to get data from server and afterwards I need to do few things with that data and other functions.
Because I'm getting data from server I did it with async and continuewith functions.
This is my code:
private void login(object sender, EventArgs eventArgs)
{
SharedFunctions.showHide("Show", pBar, txt);
result = false;
if (validateScreen())
{
Task task = new Task(() => LoginUser().ContinueWith((t) =>
{
afterLogin();
}));
task.Start();
}
}
private void afterLogin()
{
if (result)
{
SharedFunctions.saveDataOnDevice(userID, storeID, permission);
StartActivity(typeof(SplashScreen));
Finish();
}
else
{
SharedFunctions.showHide("Hide", pBar, txt);
SharedFunctions.showPopUp(this, GetString(Resource.String.error_login), GetString(Resource.String.wrong_name_and_password));
}
}
private async Task LoginUser()
{
string userName = uName.Text;
string password = pass.Text;
password = SharedFunctions.encrypt(password);
var client = new RestClient("........");
string resourceStr = #"api/base/....";
var request = new RestRequest(Method.POST)
{
Resource = resourceStr,
RequestFormat = DataFormat.Json
};
request.AddBody(new { UserName = userName, Password = password });
var response = await client.ExecuteTaskAsync<dynamic>(request);
var dt = response.Data;
if (dt != null)
{
userID = dt["ID"];
storeID = dt["StoreID"];
permission = dt["Permission"];
result = true;
}
else
result = false;
}
My main problem is that after I get the data, right after this code: if (dt != null).
When I try to debug the code it reaches the row with userID = dt["ID"]; and even before it is executed it jumps to the afterLogin() function.
What do I need to change in my code to make it run the entire functions before going to the next?
Thank you in advance!
As I describe on my blog, you should never use the Task constructor or the Start method. They are extremely outdated ways to execute code on a thread pool thread, which your app doesn't even need to do since LoginUser is asynchronous. If you did need to execute code on a thread pool thread, the correct API is Task.Run, but in this case you don't need it.
As a side note, you should not use ContinueWith in this situation, either (also explained on my blog). In fact, ContinueWith is downright dangerous; you should use await instead.
After applying these best practices:
private async void login(object sender, EventArgs eventArgs)
{
SharedFunctions.showHide("Show", pBar, txt);
result = false;
if (validateScreen())
{
await LoginUser();
afterLogin();
}
}
When it jumps out that means that the Task breaks (exception) but it doesn't break the whole program as this is an async Task.
Make a breakpoint right threre and check what is inside dt.
Especially with strings like "ID" you often have errors like these. It might be as well "Id" or "id" which is not equal nill but also not matching your "ID".
Good luck!
The problem was very different.
I found out that I cannot convert var that was in the dynamic object to int and that is why the program stopped.
I change this row: userID = dt["ID"]; to this: userID = Convert.ChangeType(dt["ID"], typeof(int));
And now it works.
Thank you all for all of your suggestions.
Task.ContinueWith starts only after completion of the original task.
I'm not sure if this'll help you but try this
private void login(object sender, EventArgs eventArgs)
{
SharedFunctions.showHide("Show", pBar, txt);
result = false;
if (validateScreen())
{
Task.Factory.StartNew(() => { LoginUser(); }).ContinueWith((t) => { afterLogin(); });
}
}
And make your login a normal void function.

Queue calls to an async method

I have an async operation named Refresh. If a second call to refresh is made before the first is finished I need to queue it. This is what I have:
public async Task Refresh(RefreshArgs refreshArgs)
{
await EnqueueRefreshTask(refreshArgs);
}
private Queue<RefreshArgs> refreshQueue =
new Queue<RefreshArgs>();
private async Task EnqueueRefreshTask(RefreshArgs refreshArgs)
{
refreshQueue.Enqueue(refreshArgs);
await ProcessRefreshQueue();
}
private Task currentRefreshTask = null;
private async Task ProcessRefreshQueue()
{
if ((currentRefreshTask == null) || (currentRefreshTask.IsCompleted))
{
if (refreshQueue.Count > 0)
{
var refreshArgs = refreshQueue.Dequeue();
currentRefreshTask = DoRefresh(refreshArgs);
await currentRefreshTask;
await ProcessRefreshQueue();
}
}
}
private async Task DoRefresh(RefreshArgs refreshArgs)
{
// Lots of code here, including calls to a server that are executed with await.
// Code outside my control may make another Refresh(args) call while this one is still processing.
// I need this one to finish before processing the next.
}
It works, but I'm not sure it's the best way to do this with Tasks. Any thoughts?
Update:
I tried using ActionBlock:
public async Task Refresh(RefreshArgs refreshArgs)
{
if (refreshActionBlock == null)
{
var executionDataflowBlockOptions = new ExecutionDataflowBlockOptions();
executionDataflowBlockOptions.MaxMessagesPerTask = 1;
executionDataflowBlockOptions.TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
refreshActionBlock = new ActionBlock<RefreshArgs>(args => DoRefresh(args), executionDataflowBlockOptions);
}
await refreshActionBlock.SendAsync(refreshArgs);
}
This queues DoRefresh, and allows it to run in the UI thread (which I need). Problem is SendAsync doesn't await on the work of DoRefresh.
SendAsync: "Asynchronously offers a message to the target message block, allowing for postponement". I'm only awaiting on the send, not the action its-self.
Doing this doesn't work as expected:
await Refresh(RefreshArgs.Something);
// other code goes here. It expects the first refresh to be finished.
await Refresh(RefreshArgs.SomethingElse);
// other code goes here. It expects the second refresh to be finished.
The ActionBlock will queue the second refresh, but the awaits fall through before the refresh is done. I need them to return when the work of DoRefresh is done.
I think the simplest way to do this is to use an AsyncLock. You can get one from Stephen Cleary's library AsyncEx, or you can read Stephen Toub's article about how to build it yourself.
When you have AsyncLock, implementing your Refresh() is straightforward:
public async Task Refresh(RefreshArgs refreshArgs)
{
using (await m_lock.LockAsync())
{
// do your async work here
}
}
This will make sure the Refresh()es execute one after the other (and not interleaved) and also that the Task returned from Refresh() completes only after the Refresh() is actually done.
You could use ActionBlock from TPL Dataflow to do the same, but you would also need to use TaskCompletionSource and it would be much more complicated than the AsyncLock version.
you can take a look at these posts, they talk about asynchronous coordination (semaphores, reset events) and exclusion using tasks:
Building Async Coordination Primitives, Part 1:
AsyncManualResetEvent
Building Async Coordination Primitives, Part 2:
AsyncAutoResetEvent
Building Async Coordination Primitives, Part 4: AsyncBarrier
Building Async Coordination Primitives, Part 5: AsyncSemaphore
[Edit: add part 6]
Building Async Coordination Primitives, Part 6: AsyncLock
This is very easy :)
Only u have need to use " switch - case " !!
now Let's go to show u how to do with small sample code .
sample scenario : we want to download 2 pic , one after another as a queue.
namespace Test
{
public partial class SampleOfQueue : Form
{
public SampleOfQueue() { InitializeComponent(); }
DBContext db = new DBContext();
int Queue;
private void btnStartApp_Click(object sender, EventArgs e)
{
Queue = 0;
DownloadQueue();
}
private void DownloadQueue()
{
switch (Queue)
{
case 0:
{
DownloadFile("http://images.forbes.com/media/lists/53/2009/tom-cruise.jpg", "Tom Cruise 1", "");
Queue += 1; break;
}
case 1:
{
DownloadFile("https://upload.wikimedia.org/wikipedia/commons/6/69/Tom_Cruise_Collateral.jpg", "Tom Cruise 2", "");
Queue += 1; break;
}
case 2:
{
// Other....
Queue += 1; break;
}
default: break;
}
}
public void DownloadFile(string urlAddress, string ImageName, string ImageFarsiName)
{
WebClient webClient = new WebClient();
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
Uri URL = urlAddress.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ? new Uri(urlAddress) : new Uri(urlAddress);
webClient.DownloadFileAsync(URL, "d:\\x.jpg");
}
private void Completed(object sender, AsyncCompletedEventArgs e)
{
DownloadQueue();
if (Queue == 3) { MessageBox.Show("finish"); }
}
}
}
Tested with C# 4.6 in VS 2015 windows form.
Innovative method of myself :)
I hope to be useful <3
Good luck.

Categories

Resources