I’ve recently had the problem of trying to display a progress dialog when executing an asynchronous operation and to dismiss that progress dialog when the operation completes.\n\nI wanted to build a way to do this that is generic to my application, so that it would work with any asynchronous operation in order to reduce duplication of writing progress dialog logic everywhere in the code.\n\n
\n\n
\n\n
Looking at the problem
\n\nSo here is some basic pseudo-code of the problem.\n\n
\n\nNow the problem with this code is that it would have to be repeated everywhere I want to make an asynchronous call and display a progress dialog.\n\nIf I want to do this in my application every time that I make an asynchronous call, I have to put this kind of code in many places in the application.\n\nYou can also see a mixing of responsibilities here. We are handling UI related showing of a progress dialog split between an initial call and the callback. It just seems a bit dirty to do things this way.\n\n
Breaking it down
\n\nSo how can we solve this problem?\n\nGo ahead and think of some way that you might be able to solve this.\n\n…\n\nOne of the best ways that I have found to solve any problem like this is to work backwards.\n\nLet us assume that any syntax we can think of is possible, and then only change the ideal syntax if it proves to not be possible.\n\nWhat do I mean by this?\n\nSimple, let’s come up with the way we want this code to look and we will worry about implementing it later.\n\nIt would be nice to be able to execute an asynchronous method and display a progress dialog with a one-liner, like so:\n\n
\n\nIf we could just do this wherever we want to make an asynchronous call and automatically have the progress dialog shown and dismissed, life would be wonderful.\n\n
Solving the problem
\n\nIn order to solve this problem, we can do something very similar to a decorator pattern.\n\nWe can basically just wrap our callback method with a new callback that adds the functionality of dismissing our progress dialog.\n\nSo the idea will be that we will do the following steps in our ExecuteAsync method:\n\n
- \n
- Show the progress dialog
- Wrap our callback with one that dismisses our dialog and then executes the callback.
- Execute our asynchronous operation passing the new wrapped callback as the parameter.
\n
\n
\n
\n\n
\n\nHere is what this looks like in code:\n\n
\n\nThis code actually looks more complicated than it really is.\n\nYou will need to understand how Action works though. If you don’t, check out this post I did explaining Action and Func.\n\n
Understanding the solution
\n\nIt can be a bit hard to wrap your head around Action of type Action of type Result.\n\nLet me translate this to make it a bit easier.\n\nThe first parameter to ExecuteAsync is a method that takes another method as a parameter (the callback,) which takes a Result object as a parameter.\n\nGo ahead and read that over until you get it.\n\nSo, the idea here is that we are passing in the method that is going to do the callback as the first parameter to your ExecuteAsync method.\n\nThen we are passing in our actual callback as the 2nd parameter to ExecuteAsync.\n\nThe idea is that we are splitting apart the method and the callback it takes, so that we can insert our code to handle the dialog where we need to.\n\nNow we can just call ExecuteAsync and pass it our method and its callback and progress dialog code will automatically be handled for us.\n\n
Building on the idea
\n\nWe can expand upon this concept in several ways.\n\nOne thing we could do is also apply error handling logic to the callback wrapper method. We could preprocess the result in some way before passing it to the callback. This could allow us to display an error message or even retry a number of times before executing the callback.\n\nAnother thing we could do is to change the signature of the ExecuteAsync method so that it takes a type T instead of Result; this would allow us to handle any kind of return type and method, and the ExecuteAsync method would work with just about any asynchronous method call.