1


I have created an application with threads( this is my first Threading application)
i have a WPF which on button click will open an excel take the ProductID's and search it in the website and return wit few details if it exists
i have created and it is working fine.
but in UI i want to display a progress bar and the current product i am searching
so i have tried it using threads.
even after this my UI is freezing. can anyone please help me out here

this is my code on click in WPF

private void btnSubmt_Click(object sender, RoutedEventArgs e)
    {
        ValidateWork obj = new ValidateWork();
        obj.notifyCompleteEvent += new EventHandler(obj_notifyCompleteEvent);
        obj.updateUI += new EventHandler<NotifyEventArgs>(obj_updateUI);

        if (string.IsNullOrEmpty(TxtbxFlePth.Text))
        {
            MessageBox.Show("Please Select a Excel File to Validate");
            return;
        }
        Excel.Application exclCrtApp = new Excel.Application();
        Excel.Workbook exclWrkBuk = exclCrtApp.Workbooks.Open(TxtbxFlePth.Text, ReadOnly: true);
        Excel.Worksheet exclWrkSht =( Excel.Worksheet) exclWrkBuk.Worksheets[1];
        PrgrsBar.Maximum = exclWrkSht.Range[exclWrkSht.Range["A2"], exclWrkSht.Range["A1048576"].End[Excel.XlDirection.xlUp]].Rows.Count;
        obj.fnStrt(exclWrkSht);

        string strSaveName = exclWrkBuk.FullName.ToString();
        strSaveName = strSaveName.Substring(0, strSaveName.IndexOf(".xls"));
        exclCrtApp.DisplayAlerts = false;
        exclWrkBuk.SaveAs(strSaveName+"_output.xlsx");
        exclWrkBuk.Close(false);
        exclCrtApp.DisplayAlerts = true;
        exclCrtApp.Quit();
        exclCrtApp = null;
    }


this is my class which has the tread calling and does all the work

class ValidateWork
{
    bool blnBrwRedy = false;
    public event EventHandler notifyCompleteEvent;      //event hander to notify the completion
    public event EventHandler<NotifyEventArgs> updateUI;    //event handler to notify UI for progress

    ManualResetEvent resumeUI = new ManualResetEvent(false);
    //first program the click calls
    public void fnStrt(Excel.Worksheet exclWksPass) 
    {
        Thread Trailtrd = new Thread(() => fnValidate(exclWksPass));            
        Trailtrd.SetApartmentState(ApartmentState.STA);
        Trailtrd.Name = "classfuncallthread";
        Trailtrd.Start();
        resumeUI.WaitOne();            
    }

    //worker thread
    public void fnValidate(Excel.Worksheet exclWksPass)
    {
        Excel.Range exclRngManHdr, exclRngCrtRow, exclRngOutUrl,exclRngAllPrd;
        string strGoglLnk = "https://www.newark.co.in/search?q=";
        StringBuilder strbldSrcRes = new StringBuilder();
        byte[] bytBuffResp=new byte[8192];
        string[] strResltUrl=new string[4];

        exclRngManHdr = exclWksPass.Range[exclWksPass.Range["A1"], exclWksPass.Range["VI1"].End[Excel.XlDirection.xlToLeft]];
        exclRngOutUrl = exclWksPass.Range["VI1"].End[Excel.XlDirection.xlToLeft].Offset[0,1];
        exclRngAllPrd = exclWksPass.Range[exclWksPass.Range["A2"], exclWksPass.Range["A1048576"].End[Excel.XlDirection.xlUp]];

        foreach (Excel.Range exclRngEchRow in exclRngAllPrd)
        {
            onupdateUI(exclRngEchRow.Row);
            string strSrchQry, strSupWeb = "";
            strSrchQry = exclRngEchRow.Text ;
            strSupWeb = exclRngEchRow.Offset[0, 2].Text.ToString();
            if(strSupWeb.Length>4)
            {
                strSupWeb = strSupWeb.Substring(strSupWeb.IndexOf("www") + 4);
            }

            WebBrowser webBrwser = new WebBrowser();
            webBrwser.ScriptErrorsSuppressed = true;

            webBrwser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrwser_DocumentCompleted);
            webBrwser.Navigate(strGoglLnk+strSrchQry+"+"+ exclRngEchRow.Offset[0, 1].Text);

            do
            {
                //as using the web forms browser using doevents
                System.Windows.Forms.Application.DoEvents();
            } while (webBrwser.ReadyState != WebBrowserReadyState.Complete);

            strResltUrl = webResltSerch(webBrwser, strSupWeb.ToUpper(), strSrchQry);
            while (strResltUrl == null || (strResltUrl[0].Contains("Part Not Found")))
            {
                strSrchQry = ModifedInput(strSrchQry) ;
                if (strSrchQry.Length < 6) { break; }
                webBrwser.Navigate(strGoglLnk + strSrchQry+ "+" + exclRngEchRow.Offset[0, 1].Text);
                do
                {
                    System.Windows.Forms.Application.DoEvents();
                } while (webBrwser.ReadyState != WebBrowserReadyState.Complete);
                strResltUrl = webResltSerch(webBrwser, strSupWeb.ToUpper(), strSrchQry);

            }//while loop
            exclWksPass.Cells[exclRngEchRow.Row, exclRngOutUrl.Column].Value = strResltUrl[0];
            exclWksPass.Cells[exclRngEchRow.Row, exclRngOutUrl.Column+1].Value = strResltUrl[1];
            exclWksPass.Cells[exclRngEchRow.Row, exclRngOutUrl.Column+2].Value = strResltUrl[2];
            exclWksPass.Cells[exclRngEchRow.Row, exclRngOutUrl.Column + 3].Value = strResltUrl[3];
            webBrwser.Dispose();
            webBrwser = null;
        }

        if (notifyCompleteEvent != null)
        {
            notifyCompleteEvent(this,EventArgs.Empty);
        }
        resumeUI.Set();
    }

    void webBrwser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
    {
        WebBrowser crntBrws = sender as WebBrowser;
        if (crntBrws.ReadyState==WebBrowserReadyState.Complete)
        { 
            blnBrwRedy = true;
            System.Diagnostics.Debug.Print("Loaded page " + crntBrws.Url.AbsolutePath); 
        }

    }


    private void onupdateUI(long CrntPrgrs)
    {
        var handler = updateUI;
        if (handler != null)
        {
            handler(this, new NotifyEventArgs(CrntPrgrs));
        }
    }

    public string[] webResltSerch(WebBrowser brwser,string OrigUrl,string OrgPrtnumb)

    {
        //searching the website
    }
}

There is no problem with the UI getting updated the progress bar is showing fully updated( when it comes back after freezing)
but the window is blank

2 Answers 2

1

The reason it's still freezing is because you're asking the UI to wait until the ManualResetEvent has been set.

The UI thread will just stop at your WaitOne() line until you Set the event, causing everything to lock up.

I'd consider using the BackgroundWorker instead; that supports progress indication and will allow you to pass your Excel.Worksheet as you're currently doing. Don't wait for the Trailtrd thread on the UI thread if you require the UI to still be responsive.

Here's a nice example of a BackgroundWorker with progress indication.

Sign up to request clarification or add additional context in comments.

3 Comments

@manuvishwanath, just use BackgroundWorker, handle the OnRunWorkerCompleted event and place your save in there.
thanks i will try this. i am trying with my first thread so was exploring all the possibilites
it works..... but i want to use threads separately. so will try threads. thank you.
0

You are asking your UI thread to wait for the new Validation thread to finish by calling resumeUI.WaitOne();

You already had the right idea when you create the notifyCompleteEvent and you already are registered to it, all you have to do is remove the resumeUI.WaitOne() call and do the completion logging in obj_updateUI eventHandler

-------EDIT---------

public void fnStrt(Excel.Worksheet exclWksPass) 
{
    Thread Trailtrd = new Thread(() => fnValidate(exclWksPass));            
    Trailtrd.SetApartmentState(ApartmentState.STA);
    Trailtrd.Name = "classfuncallthread";
    Trailtrd.Start();                  
}

private void btnSubmt_Click(object sender, RoutedEventArgs e)
    {
        ValidateWork obj = new ValidateWork();
        obj.notifyCompleteEvent += new EventHandler(obj_notifyCompleteEvent);
        obj.updateUI += new EventHandler<NotifyEventArgs>(obj_updateUI);

        if (string.IsNullOrEmpty(TxtbxFlePth.Text))
        {
            MessageBox.Show("Please Select a Excel File to Validate");
            return;
        }
        Excel.Application exclCrtApp = new Excel.Application();        
        Excel.Worksheet exclWrkSht = // get the relevant worksheet

        //if you are always working on a single worksheet then just handle it as a data member  other wise add it to notifyCompleteEvent as an argument

    obj.fnStrt(exclWrkSht);

}

now when the event handler will get called

void obj_notifyCompleteEvent()
{

  // DO your UI logic here 
  // note no need to use the dispatcher

  //now its time to save 
  string strSaveName = exclWrkBuk.FullName.ToString();
  strSaveName = strSaveName.Substring(0, strSaveName.IndexOf(".xls"));
  exclCrtApp.DisplayAlerts = false;
  exclWrkBuk.SaveAs(strSaveName+"_output.xlsx");
  exclWrkBuk.Close(false);
  exclCrtApp.DisplayAlerts = true;
  exclCrtApp.Quit();
  exclCrtApp = null;


}

5 Comments

can you please elaborate a bit on >"do the completion logging in obj_updateUI eventHandler". just didnt get what i must do
@manuvishwanath I guess after validation thread has completed you probably would like the User to know or some how update the UI, what I meant that the event handler is exactly the place to do all your UI changes (it will run on UI thread)
i have written it. and used it also to update the UI. using Dispatcher.but still it freezes. and as you can notice i save the work book. if i dont call waitone(), it will just save before the work even starts.
it worked.... thanks. i will try again on different things. no will have to make it cancel-able. is there any way you know. i know background worker has a built in option.
@manuvishwanath read this post codeproject.com/Articles/518856/… it should help

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.