Blog Archives

C# Application Not Responding Issue on Long Running Threads

Undoubtedly many of you have encountered the dreaded “Application Not Responding” message, programmers and non-programmers alike.

In general, this is caused by the OS misinterpretation of long delays in form refresh, even though these can easily be caused by a long running process, or any running process longer than a couple seconds actually.

If this is happening in your application after clicking on a button or event fires, a quick solution would be the easy one-liner below:

Application.DoEvents();

However, to really understand why this happening, remember that all processes (may) contain multiple threads.

In the case of your typical quick shot solution that you put together in VS in no-time, you’re likely only using a single thread.

This thread is used not only to run the processes in your application, but also to update the form window including drawing the fields and various controls on the form.

The best solution to this would really be to create a separate thread and pass off the work of your long running function to this thread.

When the work is finished, it will update our main thread (the form thread) that it has completed which we can intercept with a delegate, and notify the user of success or failure.

See snippet below.

private BackgroundWorker hardworker; //this guys works hard!
private System.Timers.Timer lazyworker; //notice how this could also be achieved with thread/timer

protected void btnDoAlotOfWork_Click() {
//lets see who accomplishes more!
ClockInLazyWorker();
ClockInHardWorker();
}

private void ClockInLazyWorker() {
lazyworker = new System.Timers.Timer(); //not to be confused with forms timer
lazyworker.Interval = 1000; //time in milliseconds. 10 seconds is lazy for a computer!
            lazyworker.Elapsed += new System.Timers.ElapsedEventHandler(LetsGetAMoveOnIt());
}

private void ClockInHardWorker() {
hardworker= new BackgroundWorker();
            mCopier.DoWork += DoWork; //all the heavy lifting is done here
            mCopier.RunWorkerCompleted += WorkCompleted();
            mCopier.WorkerSupportsCancellation = true;
            OnError += ProblemWithWork();
}

//motivational function name made especially for our lazy worker
private void LetsGetAMoveOnIt() {
//do something that takes a long time
//if the data you operate on is the same as used by another thread or the form thread, make sure you wrap this block in a synclock or use a bool to track when work is in process
}

//created separate function for the background worker, and also to avoid synclock issues since there are two new active threads
private void DoWork() {
//if the data you operate on is the same as used by another thread or the form thread, make sure you wrap this block in a synclock or use a bool to track when work is in process. same goes for timer.
}

private void WorkCompleted() {
//all finished
}

private void ProblemWithWork() {
//hopefully not an injury on the job! that's workmans comp!
}

Alot more code than simply “Application.DoEvents”.. but do not underestimate the power of multiple threads!

Get Selected Item from ListBox in Winforms C# and VB .Net

Iterate through all items:

  foreach(ListItem item in ListBox1.Items)
    {
       if (item.Selected == True)
       {
          //item.Value //no to be confused with text
          //item.Text //text displayed on UI
       }
    }

Find specific item text:

  private string GetSelectedItem(ListBox container)
        {
            //string selecteditem = "";
            for (int i = 0; i < container.Items.Count; i++)
            {
                if (container.Items[i].Selected == true)
                {
                    //use .value alternatively if you are trying to get value instead of text
                    return ListBox1.Items[i].Text; //breaks the loop or
                    //break; //if you decide to use without a function
                }
            }
            return ""; //error handled in calling func, remove return value if used without a function
            //return selecteditem ; //if you want to iterate all items anyway
        }

More generalized for re-usability to get text or value, though a little less readable and alot more code:

private static class GetSelectedItem {
private enum ListBox_ContentType {
Text,
Value
}

public string Text(ListBox container) { Get_ContentType(container,ListBox_ContentType.Text);}
public string Value(ListBox container) { Get_ContentType(container,ListBox_ContentType.Value);}

private string Get_ContentType(ListBox container, ListBox_ContentType ContentType) {
  for (int i = 0; i < container.Items.Count; i++)
            {
                if (container.Items[i].Selected == true)
                {
if (ContentType == ListBox_ContentType.Value) {
return ListBox1.Items[i].Text;
}
else //ContentType == ListBox_ContentType.Value 
{
                    return ListBox1.Items[i].Value;
}
                }
            }
            return "";
}
}

Change WPF Toolbar and Window Skin

Took me some Googling to come across some good links to help me find exactly what I was looking to do. Hopefully my post gets enough hits that you’ll come across my title sooner rather than later, and can benefit from my time and research. 🙂

If you’re new to WPF, or even if you’ve been using WPF for some quite some time, you may or may not have noticed that theming and skinning is not relatively straight forward, and there are many different ways to achieve the end result visually.

If you’re using WPF simply to learn the new technology, understand that there are pro’s and con’s to WPF vs standard Winforms, and although the latter is technically “legacy”, depending on third party controls you may or may not be using, implementation in Winforms can be very fast and may still be a better option for some projects.

Here’s a simple grid I’ve come up with to help you decide which to use:

  WinForms WPF
Supports Skins No Yes
Uses graphics resources to render No Yes
Easily bind controls with data No Yes
Easy to design a form with drag+drop Yes No
Some cross-platform compatibility with Mono Yes No
Easily customize look and feel of controls No Yes
Already comes with most controls/visuals needed for business app Yes No

As you can see from the table above, if you are trying to quickly knock out a business app that is not going to require heavy visual modification or too reliant on databinding, it’s probably faster in WinForms. Also, I have personally deployed WinForms cross-platform (Mac, Linux) using mono, which I could not get to work with WPF.

Overall though, for most environments, WPF is usually the way to go if not for visual flexibility then for databinding (why are you using windows client apps again?:P).

One ways listed above that WPF really comes out on top is in utilizing the computer’s graphics card and other graphics resources to render forms. The WPF objects on the screen are still contained in a form however, and many theming examples override the draw methods on the forms themselves which don’t properly utilize the effectiveness of WPF.

In general, I have found there are at least three different ways to change the look and feel of your application in WPF:

Using Silverlight Themes
Using Office Themes
Using your own Custom Themes

If you download and install the Silverlight toolkit (not to be confused with silverlight SDK or silverlight client), you will automatically get multiple dll references which contain XAML themes that can be re-used in WPF. This is a quick way to make your WPF app look good without too much work.

Office themes are pre-built in, and a common choice for many beginner WPF skinners. They share common visuals which you see in many office apps and give your application a more up-to date look and feel with some recognizability by your users also, similar to how Mac applications all share a common theme.

This is also always an option, but be prepared for a long and ardous task and a few lunch days with your favorite designer. Microsoft expressions studio comes with all the tools needed to make your controls as beautiful as you like, and implementing and inheriting from these visuals is actually relatively simple, but when you apply the time it takes to make one control by the amount of different controls you may have, there is alot of work involved. Also for re-usability, you’ll want to put all your custom controls/skins in their own assembly which increases the time even further. If you’re short on time (who isn’t :P), this is not a good option, but in the long-run this could be very beneficial and give your applications their own gleam.

See references for links on how to implement the above and other information regarding skinning and theming in WPF. (The reference links are in order of my google “stream of consciousness” :P)

References
WPF Skins (this blog), <a href="https://ronniediaz.wordpress.com/wp-admin/post.php?post=1250&action=edit
MSDN Blog, http://social.msdn.microsoft.com/forums/en-us/wpf/thread/c87d508b-9195-4a68-831f-315b64520fcf
Codeproject Article, http://www.codeproject.com/KB/WPF/WPFBusinessAppsPartOne.aspx
Stackoverflow Blog, http://stackoverflow.com/questions/260098/any-free-wpf-themes
Codeplex Article, http://wpfcontrib.codeplex.com/wikipage?title=Themes&referringTitle=Home&ProjectName=wpfcontrib
WPF Tutorial.Net, http://www.wpftutorial.net/Expander.html
Silverlight.Net Blog, http://blogs.silverlight.net/blogs/msnow/archive/2009/02/09/silverlight-tip-of-the-day-91-how-to-apply-themes-from-the-silverlight-toolkit.aspx
MSDN Social, http://social.msdn.microsoft.com/forums/en-US/wpf/thread/3c66adb7-fd26-40c7-8404-85f6fefbd392/
C-sharp Corner Article, http://www.c-sharpcorner.com/Resources/Detail.aspx?ResourceId=667
Browsoft Article, http://www.browsoft.com/tutorials/DefaultTheme.html
Jan-Cornelius Molnar (Blog), http://www.vb-magazin.de/forums/blogs/janm/archive/2006/06/19/4655.aspx
MSDN Official Blog, http://blogs.msdn.com/b/wpfsdk/archive/2008/09/08/custom-window-chrome-in-wpf.aspx

URL Decode in WPF

Crossing from web to forms development you may notice System.Web is not available. You could extract it from the GAC, but would suffer from having to manually update it moving forward.

One solution on the web suggested using Microsoft.XSS library (which is up to version 4.0 at the time of this article).

This would work, but there are some differences in string conversion, especially regarding the “+” and “~” character between using the Web UrlEncode/UrlDecode found in the XSS library or using the Uri method illustrated below.

See references for links to XSS and/or information regarding the differences on how these strings are encoded differently with each method.

Uri videouri = new Uri(AppDomain.CurrentDomain.BaseDirectory + "../../Videos/directory/player.htm");

            string videourl = Uri.UnescapeDataString(videouri.ToString());

            webBrowser1.Navigate(videourl); //can actually accept uri or string

References
Microsoft Anti-XSS Library 4.0, http://www.microsoft.com/downloads/en/details.aspx?FamilyID=F4CD231B-7E06-445B-BEC7-343E5884E651
Nerdbank, http://blog.nerdbank.net/2009/05/uriescapedatapath-and.html
StackOverflow, http://stackoverflow.com/questions/36315/alternative-to-httputility-for-net-3-5-sp1-client-framework

Winforms Databinding

Snippets below have been condensed from their original sources for brevity. See references for original articles.

Dataset usage:

using System;
using System.Data;
using System.Data.SqlClient;

namespace Microsoft.AdoNet.DataSetDemo
{
    class NorthwindDataSet
    {
        static void Main()
        {
            string connectionString = GetConnectionString();
            ConnectToData(connectionString);
        }

        private static void ConnectToData(string connectionString)
        {
            //Create a SqlConnection to the Northwind database.
            using (SqlConnection connection =
                       new SqlConnection(connectionString))
            {
                //Create a SqlDataAdapter for the Suppliers table.
                SqlDataAdapter adapter = new SqlDataAdapter();

                // A table mapping names the DataTable.
                adapter.TableMappings.Add("Table", "Suppliers");

                // Open the connection.
                connection.Open();
                Console.WriteLine("The SqlConnection is open.");

                // Create a SqlCommand to retrieve Suppliers data.
                SqlCommand command = new SqlCommand(
                    "SELECT SupplierID, CompanyName FROM dbo.Suppliers;",
                    connection);
                command.CommandType = CommandType.Text;

                // Set the SqlDataAdapter's SelectCommand.
                adapter.SelectCommand = command;

                // Fill the DataSet.
                DataSet dataSet = new DataSet("Suppliers");
                adapter.Fill(dataSet);

                // Create a second Adapter and Command to get
                // the Products table, a child table of Suppliers. 
                SqlDataAdapter productsAdapter = new SqlDataAdapter();
                productsAdapter.TableMappings.Add("Table", "Products");

                SqlCommand productsCommand = new SqlCommand(
                    "SELECT ProductID, SupplierID FROM dbo.Products;",
                    connection);
                productsAdapter.SelectCommand = productsCommand;

                // Fill the DataSet.
                productsAdapter.Fill(dataSet);

                // Close the connection.
                connection.Close();
                Console.WriteLine("The SqlConnection is closed.");

                // Create a DataRelation to link the two tables
                // based on the SupplierID.
                DataColumn parentColumn =
                    dataSet.Tables["Suppliers"].Columns["SupplierID"];
                DataColumn childColumn =
                    dataSet.Tables["Products"].Columns["SupplierID"];
                DataRelation relation =
                    new System.Data.DataRelation("SuppliersProducts",
                    parentColumn, childColumn);
                dataSet.Relations.Add(relation);
                Console.WriteLine(
                    "The {0} DataRelation has been created.",
                    relation.RelationName);
            }
        }

        static private string GetConnectionString()
        {
            // To avoid storing the connection string in your code, 
            // you can retrieve it from a configuration file.
            return "Data Source=(local);Initial Catalog=Northwind;"
                + "Integrated Security=SSPI";
        }
    }
}

Binding DataGridView:

private void GetData(string selectCommand)
{
    try
    {
        // Specify a connection string. Replace the given value with a 
        // valid connection string for a Northwind SQL Server sample
        // database accessible to your system.
        String connectionString =
            "Integrated Security=SSPI;Persist Security Info=False;" +
            "Initial Catalog=Northwind;Data Source=localhost";

        // Create a new data adapter based on the specified query.
        dataAdapter = new SqlDataAdapter(selectCommand, connectionString);

        // Create a command builder to generate SQL update, insert, and
        // delete commands based on selectCommand. These are used to
        // update the database.
        SqlCommandBuilder commandBuilder = new SqlCommandBuilder(dataAdapter);

        // Populate a new data table and bind it to the BindingSource.
        DataTable table = new DataTable();
        table.Locale = System.Globalization.CultureInfo.InvariantCulture;
        dataAdapter.Fill(table);
        bindingSource1.DataSource = table;

        // Resize the DataGridView columns to fit the newly loaded content.
        dataGridView1.AutoResizeColumns( 
            DataGridViewAutoSizeColumnsMode.AllCellsExceptHeader);
    }
    catch (SqlException)
    {
        MessageBox.Show("To run this example, replace the value of the " +
            "connectionString variable with a connection string that is " +
            "valid for your system.");
    }
}

References:
MSDN, “DataSet Class”, http://msdn.microsoft.com/en-us/library/system.data.dataset.aspx

MSDN, “How to: Bind Data to the Windows Forms DataGridView Control”, http://msdn.microsoft.com/en-us/library/fbk67b6z.aspx