DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
The Latest "Software Integration: The Intersection of APIs, Microservices, and Cloud-Based Systems" Trend Report
Get the report

Avoid UI freezes at all costs, if possible

Denzel D. user avatar by
Denzel D.
·
Jul. 20, 10 · Interview
Like (0)
Save
Tweet
Share
16.41K Views

Join the DZone community and get the full member experience.

Join For Free

Applications tend to perform various resource-consuming operations and there is not much we as developers can change about that. In fact, developers don’t want to change that – mainly, because that is the purpose of those applications.

Introduction

If the application is running as a service, then the methods described in this article don’t apply to it - basically because services don't have an independent UI whatsoever. This article applies to client desktop applications that are running outside the console with a graphical UI (WinForms and WPF specifically).

To clearly demonstrate the impact of a resource-consuming process on the application, here is a real example of a method that can cause the UI to freeze:

void GetList()
{
var cities = new List<string>();

XmlDocument doc = new XmlDocument();
try
{
doc.Load("http://www.webservicex.net/uszip.asmx/GetInfoByState?USState=TX");
foreach (XmlNode node in doc.SelectSingleNode("NewDataSet"))
{
XmlNode childNode = node.SelectSingleNode("CITY");
string city = childNode.InnerText;
if (!cities.Contains(city))
{
cities.Add(city);
}
}
}
catch
{
MessageBox.Show("Error fetching data from server.", "Application", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}

Via this method I am able to retrieve the full list of cities registered for a specific US state (Texas in this testing case). Roughtly saying, it depends on the service performance, but is also stopping the UI from responding while it is retrieving the data. This is not the most pleasant experience for end-users and if it continues for a little while, it might end up with the user terminating the application the “cold” way by killing the process. And there shouldn't be a long explanation on what a "cold" application termination might cause - at least the current data will be lost or become corrupt.

Users tend not to wait much once the UI becomes unresponsive.

To avoid this, it would be reasonable to move the resource-consuming process in another thread. That way, the UI thread will remain responsive to user input, but the process will be running in the background.

There are two ways to implement this. The first one is by using the regular Thread class. The second one is by using BackgroundWorker.

BackgroundWorker

If you are going to use BackgroundWorker, there are several “benefits” you gain. First of all, it offers easier UI communication from the background thread. This can be handled via the ProgressChanged and RunWorkerComplete event handlers.

The main method that actually performs all he background work is DoWork. Applied to my method, I would have to create a new instance of BackgroundWorker, create a DoWork event handler and call the method from there:

BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);

void worker_DoWork(object sender, DoWorkEventArgs e)
{
GetList();
}

Then, you can track the execution of the background process by checking the IsBusy property, which will tell the developer whether the process is still running or not.

Once the process is finished, RunWorkerComplete is automatically triggered (in case it is set) – you can push notifications via this method or perform some finishing tasks.

NOTE: The thread started by a BackgroundWorker is a background thread.

Thread

If you are going to use the Thread class to manage an operation, you will have to manually handle the thread interaction between the UI thread and the one started for a specific task. However, one interesting thing about the Thread class is that it offers you control over the thread priorities. Although this might be a risky practice due to the way Windows prioritizes and handles threads, this might be important to implement when you are aware of the consumed resources and the impact on other threads.

To move a process to a background thread via the Thread class, you could use the following code (structure might change depending on the passed method):

Thread t = new Thread(new ThreadStart(GetList));
t.IsBackground = true;
t.Start();

I am explicitly setting the thread as a background one. What is the difference, you might ask? Foreground threads basically decide whether the process continues to run or not. If there are no running foreground threads, then the process is automatically killed. This, however, does not apply to background threads.

Setting my thread to be a background one is a good idea since while it is executing, the user might decide to close the application. If it remains as a foreground thread, then the UI thread will terminate, but the application will still be waiting for this thread to complete and that is not something you’d want.

Conclusion

Using either of the above methods will ensure that your application will provide a decent user experience and won’t cause frustration from the client’s side once a high processing point is hit. Although threading is one topic several of developer groups try to avoid unless necessary, I would say that implementing a threaded application brings more benefits than risks. With a little bit more effort on the developer's side, the end-user will avoid frustration later on when something could go wrong with an operation.

application

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Introduction Garbage Collection Java
  • Orchestration Pattern: Managing Distributed Transactions
  • Documentation 101: How to Properly Document Your Cloud Infrastructure Project
  • Reliability Is Slowing You Down

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: