Resolved Cross-thread problem control

aaaron123

Member
Joined
Jan 3, 2021
Messages
16
Programming Experience
1-3
C#:
 //The "while" below cause and exception:
        //System.InvalidOperationException:'Cross-thread operation not valid: Control lstFiles accessed from thread other than the thread it was created on.'
        private void watchFinished()
        {
            do
            {
                Thread.Sleep(50);
            }
            while (lstFiles.CheckedItems.Count != 0);

            showProgress(prgHole, 100);

            string ans = "Done";

            if (undeletable.Count != 0)
            {
                string[] items = new string[undeletable.Count];

                undeletable.CopyTo(items, 0);

                frmUndeletable frm = new frmUndeletable(items);

                frm.ShowDialog();
            }
            else
                ans += ", No Items TO Delete";


            MessageBox.Show(ans + " : " + prg.ToString() + " files deleted");
        }


Please bear with me, I don't write C# but I have a C# program that I need and it gives the error mentioned above.

I have no need to learn C# but I do need the program and would appreciate it if you would tell me how to fix it.

If I didn't give enough info above, maybe you can just give me something to try.

In any event, I'd appreciate any help at all.
 
Solution
I would recommend against that but, if that's what you want to do, you should take the following steps:

1. Write a method that does what you want to:
C#:
private bool AreAnyItemsChecked()
{
    return lstFiles.CheckedItems.Count != 0;
}
2. Add the use of InvokeRequired and Invoke:
C#:
private bool AreAnyItemsChecked()
{
    if (lstFiles.InvokeRequired)
    {
        // We are on a secondary thread so reinvoke the same method on the UI thread.
        return (bool)lstFiles.Invoke(new Func<bool>(AreAnyItemsChecked));
    }
    else
    {
        // We are on the UI thread so perform the desired action.
        return lstFiles.CheckedItems.Count != 0;
    }
}
3. Call that method where you previously had the offending code...

jmcilhinney

C# Forum Moderator
Staff member
Joined
Apr 23, 2011
Messages
4,250
Location
Sydney, Australia
Programming Experience
10+
That error message indicates that you are trying to access the UI from code executed on a secondary thread. That's a no-no. Firstly, you are trying to get some data from a control and that's the direct issue. Even without that though, you are then displaying a modal dialogue and a message box but, because you do so on a secondary thread, neither will actually prevent the user accessing the calling form.

You need top explain what you're actually trying to achieve in order for us the explain the correct way to achieve it. We shouldn't have to work it out from code that doesn't do it. If you want to perform an action when the user checks an item in a CheckedListBox then why aren't you handling the ItemCheck event of that control?
 

aaaron123

Member
Joined
Jan 3, 2021
Messages
16
Programming Experience
1-3
Thanks for replying.

As I said I'm not a C# programmer and it is not my code.

I don't suppose my request is in this forum's scope but I as hoping someone would want to help.

I thought that maybe knowing the error message and that cross threading was involved someone would know how to add "if (!lstFiles.InvokeRequired)" kind of statement I've seen elsewhere in the code.
 

jmcilhinney

C# Forum Moderator
Staff member
Joined
Apr 23, 2011
Messages
4,250
Location
Sydney, Australia
Programming Experience
10+
I would recommend against that but, if that's what you want to do, you should take the following steps:

1. Write a method that does what you want to:
C#:
private bool AreAnyItemsChecked()
{
    return lstFiles.CheckedItems.Count != 0;
}
2. Add the use of InvokeRequired and Invoke:
C#:
private bool AreAnyItemsChecked()
{
    if (lstFiles.InvokeRequired)
    {
        // We are on a secondary thread so reinvoke the same method on the UI thread.
        return (bool)lstFiles.Invoke(new Func<bool>(AreAnyItemsChecked));
    }
    else
    {
        // We are on the UI thread so perform the desired action.
        return lstFiles.CheckedItems.Count != 0;
    }
}
3. Call that method where you previously had the offending code:
C#:
do
{
    Thread.Sleep(50);
}
while (AreAnyItemsChecked());
 
Solution

aaaron123

Member
Joined
Jan 3, 2021
Messages
16
Programming Experience
1-3
That's impressive. Worked like a charm!

Only one typo, I think one of the AreAnyItemsChecked was meant to start with lower case.

Thanks


P.S. How do I mark it as answered?

P.P.S. I down voted by mistake, then upvoted, then marked as solution. Not sure but I'm guessing the last was what I asked about.
 
Last edited:

JohnH

C# Forum Moderator
Staff member
Joined
Apr 23, 2011
Messages
1,363
Location
Norway
Programming Experience
10+
How do I mark it as answered?
Top right:
1609703596207.png
(I just clicked it)

It changes thread prefix to "Resolved".
 

jmcilhinney

C# Forum Moderator
Staff member
Joined
Apr 23, 2011
Messages
4,250
Location
Sydney, Australia
Programming Experience
10+
I think one of the AreAnyItemsChecked was meant to start with lower case.
Nope. This is C#, not Java or JavaScript. Anyone can use whatever conventions they want but Microsoft recommend Pascal casing for method names. That's what they use themselves throughout the .NET Framework and that's what the vast majority of C# developers use, as far as I've seen. For you to start your own method names with a lower-case letter while using system or third-party methods that start with an upper-case letter is introducing inconsistency and inconsistency is always bad.

EDIT: I notice that you said "one of the AreAnyItemsChecked", so I'm not sure whether you were saying what I thought you were. I see that you named your own method with a leading lower-case letter, so I assumed that you meant that that's how methods should be named. Maybe you did, but now I'm wondering whether you were referring to this one specifically:
C#:
return (bool)lstFiles.Invoke(new Func<bool>(AreAnyItemsChecked));
In that line, it is still referring to the same method but it is not actually calling a method. That is known as a method group and it is how you create a delegate in C#. It's not calling the method at the time but it is saying that this is the method that will be executed when this delegate is invoked. The Invoke method of the control takes that delegate object, carries it across the thread boundary to the UI thread and invokes it, which then executes the specified method on the UI thread.
 
Last edited:

JohnH

C# Forum Moderator
Staff member
Joined
Apr 23, 2011
Messages
1,363
Location
Norway
Programming Experience
10+
Only one typo, I think one of the AreAnyItemsChecked was meant to start with lower case.
I think you maybe copied both 1 and 2, but 2 is just a modification of 1, where line 6 call itself by Control.Invoke.
 

aaaron123

Member
Joined
Jan 3, 2021
Messages
16
Programming Experience
1-3
That's impressive. Worked like a charm!

Only one typo, I think one of the AreAnyItemsChecked was meant to start with lower case.

Thanks


P.S. How do I mark it as answered?

P.P.S. I down voted by mistake, then upvoted, then marked as solution..
P.P.P.S Ignore the typo comment. see JohnH's reply
 
Last edited:

aaaron123

Member
Joined
Jan 3, 2021
Messages
16
Programming Experience
1-3
Nope. This is C#, not Java or JavaScript. Anyone can use whatever conventions they want but Microsoft recommend Pascal casing for method names. That's what they use themselves throughout the .NET Framework and that's what the vast majority of C# developers use, as far as I've seen. For you to start your own method names with a lower-case letter while using system or third-party methods that start with an upper-case letter is introducing inconsistency and inconsistency is always bad.

EDIT: I notice that you said "one of the AreAnyItemsChecked", so I'm not sure whether you were saying what I thought you were. I see that you named your own method with a leading lower-case letter, so I assumed that you meant that that's how methods should be named. Maybe you did, but now I'm wondering whether you were referring to this one specifically:
C#:
return (bool)lstFiles.Invoke(new Func<bool>(AreAnyItemsChecked));
In that line, it is still referring to the same method but it is not actually calling a method. That is known as a method group and it is how you create a delegate in C#. It's not calling the method at the time but it is saying that this is the method that will be executed when this delegate is invoked. The Invoke method of the control takes that delegate object, carries it across the thread boundary to the UI thread and invokes it, which then executes the specified method on the UI thread.
Thanks for the complete reply. As I said elsewhere, the typo note was well intentioned but incorrect.
 
Top Bottom