Solved

ListView Control using BackgroundWorker control questions in C#

Posted on 2008-10-22
6
2,933 Views
Last Modified: 2013-12-17
I've run into a bit of a snag and I need some reading resources, help, whatever form I can get it in.
The Form I've created is simple. I dropped a ListView control on to it, a Button and a Label to display the number of files total via my loop routine.

All I'm doing is connected to a remote Server, getting the files from this directory, and then displaying them on the ListView control. However, when I attempt to Call a method routine, I get the following error message:
"Error: Cross-thread operation not valid: Control 'lvwFilesAndFolders' (name of my ListView control)access from a thread other than the thread it was created on". (Line 65 calls PaintListView(string root)).

This happens when the "private void PaintListView(string root)" method is called from the BackgroundWorker.DoWork Event,  and it has references to the ListView Control named "lvwFilesAndFolders". How in the world do I get around this Cross-thread operation?
I have zero experience with Delegates and Multithreading in C#. It appears I'm going to probably need to build the ListView control by code in order to prevent this Cross-thread operation. Anyone have any experience or know of any articles to help me get through this? Not sure where to start.
I can't thank anyone enough,
Wallace
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
 
namespace ParseLogErrors
{
    public partial class Form1 : Form
    {
        private System.Collections.Specialized.StringCollection folderCol;
       
        public Form1()
        {
            InitializeComponent();
            this.labelFileCountDisplay.Text = "";
            CreateHeadersAndFillListView();
            //this.lvwFilesAndFolders.ItemActivate += System.EventHandler(this.lvwFilesAndFolders_ItemActivate);
        }
 
        private void buttonParseLogs_Click(object sender, EventArgs e)
        {
            string dirName = textBoxSearchPath.Text;
                        
            // Set current working directory & verify it exists
            if (Directory.Exists(dirName))
            try
            {
                Directory.SetCurrentDirectory(dirName);
                MessageBox.Show(dirName);
            }
            catch (UnauthorizedAccessException)
            {
                MessageBox.Show("Not authorized to access " + dirName);
                return;
            }
            catch (FileNotFoundException)
            {
                MessageBox.Show("No such directory: " + dirName);
                return;
            }
 
        // Init ListView and folder collection
            //folderCol = new System.Collections.Specialized.StringCollection();
            PaintListView(dirName);
            //folderCol.Add(dirName);
            //PaintListView(@"c:\c# testing");
            //folderCol.Add(@"c:\c# testing");
            //PaintListView(@"\\crprdnsrc03\logs$\sd4\regional");
            //folderCol.Add(@"\\crprdnsrc03\logs$\sd4\regional");
 
            ListView lvi = this.lvwFilesAndFolders;
            bgw.RunWorkerAsync();
        }
 
        private void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            //Lets call the other statements from here
            string dirName = textBoxSearchPath.Text;
            folderCol = new System.Collections.Specialized.StringCollection();
           PaintListView(dirName);
            //folderCol.Add(dirName); 
        }
        
        private void CreateHeadersAndFillListView()
        {
            ColumnHeader colHead;
 
            colHead = new ColumnHeader();
            colHead.Width = 500;
            colHead.Text = "Filename";
            this.lvwFilesAndFolders.GridLines = true;
            this.lvwFilesAndFolders.Columns.Add(colHead);
 
            colHead = new ColumnHeader();
            colHead.Width = 100;
            colHead.Text = "Size";
            this.lvwFilesAndFolders.GridLines = true;
            this.lvwFilesAndFolders.Columns.Add(colHead);
 
            colHead = new ColumnHeader();
            colHead.Width = 200;
            colHead.Text = "Last Accessed";
            this.lvwFilesAndFolders.GridLines = true;
            this.lvwFilesAndFolders.Columns.Add(colHead);
        }
 
        private void PaintListView(string root)
        {
            try
            {
                ListViewItem lvi;
                ListViewItem.ListViewSubItem lvsi;
 
                this.labelDisplayLogInfo.Text = root;
                DirectoryInfo dir = new DirectoryInfo(root);
 
                this.lvwFilesAndFolders.Items.Clear();
 
                DirectoryInfo[] dirs = dir.GetDirectories();
                FileInfo[] files = dir.GetFiles();
 
                this.lvwFilesAndFolders.BeginUpdate();
                
                foreach (System.IO.FileInfo fi in files)
                {
                    lvi = new ListViewItem();
                    lvi.Text = fi.Name;
                    //lvi.ImageIndex = 0;
                    lvi.Tag = fi.FullName;
 
                    lvsi = new ListViewItem.ListViewSubItem();
                    lvsi.Text = formatsizekb(fi.Length);
                    lvi.SubItems.Add(lvsi);
 
                    lvsi = new ListViewItem.ListViewSubItem();
                    lvsi.Text = fi.LastAccessTime.ToString();
                    lvi.SubItems.Add(lvsi);
 
                    this.lvwFilesAndFolders.Items.Add(lvi);
 
                    //Lets count the number of files
                    int file_count = 1;
                    foreach(FileInfo file in files)
                    {
                        this.labelFileCountDisplay.Text = Convert.ToString(file_count++);
                        //progressBar1.Step = 10;
                        //progressBar1.Minimum = 0;
                        //progressBar1.Maximum = 100;
                        //progressBar1 = (file_count * 100) / files.Length;
                    }                                  
                }
 
                this.lvwFilesAndFolders.EndUpdate();
            }
            catch (System.Exception err)
            {
                MessageBox.Show("Error: " + err.Message);
            }
 
            this.lvwFilesAndFolders.View = View.Details;
        }
    
            private void lvwFilesAndFolders_ItemActive(object sender, System.EventArgs e)
        {
            ListView lvw = (ListView)sender;
            string filename = lvw.SelectedItems[0].Tag.ToString();
            Console.WriteLine(filename);
        }
 
        private void buttonExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }
               
        //Formats File size
        private string formatsizekb(long lsize)
        {
            const int iKB = 1024;
            const long lMB = 1048576;
 
            if (lsize < iKB)
                return string.Format("{0:#,#} bytes", lsize);
            else if (lsize >= iKB && lsize < lMB) ;
                return string.Format("{0:#,#} KB", lsize / 1024);
        }
               
        private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
 
        }
 
        private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
 
        }
                
    }
}

Open in new window

0
Comment
Question by:wally_davis
  • 3
  • 3
6 Comments
 
LVL 11

Expert Comment

by:William
ID: 22782233
I have pasted the code below to overcome this for a textbox.
Please review the code and modify for type you need.
If you still need more help please post back and I will gladly help.

BillyDvd
#region Cross Threading Control Delegates for Text Set and Get
        /// <summary>
        /// Call this method to avoid cross threading exceptions when updating a controls text from another thread other than the thread that created it.
        /// </summary>
        /// <param name="Ctrl">Control to update text.</param>
        /// <param name="Text">Text to update as string.</param>
        void SetControlText( Control Ctrl , string Text )
        {
            //ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.VisualStudio.v80.en/dv_fxmclictl/html/138f38b6-1099-4fd5-910c-390b41cbad35.htm
            if ( Ctrl.InvokeRequired )
            {
                SetControlTextCallBack d = new SetControlTextCallBack( SetControlText );
                this.Invoke( d , new object[ ] { Ctrl , Text } );
            }
            else
                Ctrl.Text = Text;
        }
        delegate void SetControlTextCallBack( Control Ctrl , string Text );
 
        /// <summary>
        /// Call this method to avoid cross threading exceptions when retrieving a controls text from another thread other than the thread that created it.
        /// </summary>
        /// <param name="Ctrl">Control to get text from.</param>
        string GetControlText( Control Ctrl )
        {
            if ( !Ctrl.InvokeRequired )
                return Ctrl.Text;
            else
            {
                //http://www.codeproject.com/csharp/threadsafeforms.asp
                return ( string )Invoke( new GetControlTextCallBack( GetControlText ) , new object[ ] { Ctrl } );
            }
        }
        delegate string GetControlTextCallBack( Control Ctrl );
        #endregion

Open in new window

0
 

Author Comment

by:wally_davis
ID: 22782336
Hi Billy,
Honestly, I've been trying to get this to work with the BackgroundWorker control and I noticed that this may be a bigger challenge for me to overcome. There is nothing in the way of Tutorials out there on C# Winform Controls and threading. I can see where this works for text from a Textbox, but, I'm not sure if it will help me with the ListView Control. I've added the code above and explained as best as I could in detail what I'm attempting to accomplish. It would be nice to have someone go Step by Step to get something like this for me to work. If you want to take a crack please let me know. I would be most thankful.
0
 
LVL 11

Expert Comment

by:William
ID: 22782350
What line does it error on?
Can you post the exception?
Thanks -
0
How Do You Stack Up Against Your Peers?

With today’s modern enterprise so dependent on digital infrastructures, the impact of major incidents has increased dramatically. Grab the report now to gain insight into how your organization ranks against your peers and learn best-in-class strategies to resolve incidents.

 

Author Comment

by:wally_davis
ID: 22782728
If you read my first email thread that will cover everything.
However I did leave out which line it was occuring on.
When bw_DoWork Event is processed (on Line 60), it calls the "PaintListView(dirName);" method routine and the  the Error gets thrown at Line # 102 (see my code attachment in first thread).

0
 

Accepted Solution

by:
wally_davis earned 0 total points
ID: 22791294
needed the solution rather quickly and I didn't hear back. However, I've discovered the information I needed anyway.
0
 
LVL 11

Expert Comment

by:William
ID: 22799290
wally_davis,
Can you please post your findings so others can benifit from what you have learned?

BillyDvd
0

Featured Post

How our DevOps Teams Maximize Uptime

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us. Read the use case whitepaper.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

It seems a simple enough task, yet I see repeated questions asking how to do it: how to pass data between two forms. In this article, I will show you the different mechanisms available for you to do just that. This article is directed towards the .N…
Many of us here at EE write code. Many of us write exceptional code; just as many of us write exception-prone code. As we all should know, exceptions are a mechanism for handling errors which are typically out of our control. From database errors, t…
Microsoft Active Directory, the widely used IT infrastructure, is known for its high risk of credential theft. The best way to test your Active Directory’s vulnerabilities to pass-the-ticket, pass-the-hash, privilege escalation, and malware attacks …
The Email Laundry PDF encryption service allows companies to send confidential encrypted  emails to anybody. The PDF document can also contain attachments that are embedded in the encrypted PDF. The password is randomly generated by The Email Laundr…

828 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question