Results 1 to 9 of 9

Thread: [RESOLVED] Invoke RichTextBox From Another Thread

  1. #1

    Thread Starter
    Frenzied Member
    Join Date
    Jan 2008
    Posts
    1,754

    Resolved [RESOLVED] Invoke RichTextBox From Another Thread

    Hello, I modified some code I found after a search on google. The original code was written my jmc. It originally, on the original code, a void. I tried to modify it to work with a string[].

    I am currently getting a Parameter count error message.

    Code:
    private delegate string[] GetRtbSongsLinesDelegate(object item);
            private string[] GetRtbSongsLines(object item)
            {
                if (this.rtbSongs.InvokeRequired)
                {
                    // This is a worker thread so delegate the task.
                    this.rtbSongs.Invoke(new GetRtbSongsLinesDelegate(this.GetRtbSongsLines),null);
                }
                else
                {
                    // This is the UI thread so perform the task.
                    return this.rtbSongs.Lines;
                }
                return null;
            }
    I am calling this using:
    Code:
    GetRtbSongsLines(null)
    For example:
    Code:
    if(GetRtbSongsLines(null).length > 0){
    //There are more than 0 lines
    }
    What's wrong?

  2. #2
    Frenzied Member Lightning's Avatar
    Join Date
    Oct 2002
    Location
    Eygelshoven
    Posts
    1,611

    Re: Invoke RichTextBox From Another Thread

    At which line do you ge the error?
    VB6 & C# (WCF LINQ) mostly


    If you need help with a WPF/WCF question post in the NEW WPF & WCF forum and we will try help the best we can

    My site

    My blog, couding troubles and solutions

    Free online tools

  3. #3

    Thread Starter
    Frenzied Member
    Join Date
    Jan 2008
    Posts
    1,754

    Re: Invoke RichTextBox From Another Thread

    Code:
    this.rtbSongs.Invoke(new GetRtbSongsLinesDelegate(this.GetRtbSongsLines),null);

  4. #4
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,297

    Re: Invoke RichTextBox From Another Thread

    I address this specifically in my Accessing Controls From Worker Threads thread in the CodeBank. Go and read post #3 of that thread, which specifically deals with returning data across thread boundaries.
    Last edited by jmcilhinney; Nov 20th, 2010 at 07:20 PM. Reason: Correct post #2 to post #3

  5. #5

    Thread Starter
    Frenzied Member
    Join Date
    Jan 2008
    Posts
    1,754

    Re: Invoke RichTextBox From Another Thread

    Using your example for passing in a control as the parameter, could I essentially return the actual control instead of the text of the control and then use the returned control to access its different members/properties?

    Using those principals here is a method that returns the actual control - will this work, or is there some reason why this isn't used instead of more specific methods?
    Code:
    private delegate string GetControlTextInvoker(Control ctl);
    private string GetControlText(Control ctl)
    {
        string text;
        if (ctl.InvokeRequired)
        {
            text = (string)ctl.Invoke(new GetControlTextInvoker(GetControlText),ctl);
        }
        else
        {
            text = ctl.Text;
        }
        return text;
    }
    Last edited by noahssite; Nov 20th, 2010 at 08:59 PM.

  6. #6
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,297

    Re: Invoke RichTextBox From Another Thread

    The whole point of this delegation is that you can NOT access members of a control directly unless you're on the thread that created it. There's no point returning a control because you can;t then access it's members.

    The reason I created that CodeBank thread in the first place was to provide a simple set of steps that anyone could follow and get delegation to work. Far too many people don't want to follow the steps though. They just jump to the end and wonder why it won't work. Follow the steps as they apply to your specific scenario and it will work. Here's post #3 from the CodeBank reposted but with code appropriate to your situation. This is how easy it is if you do as instructed and follow the steps provided.
    Quote Originally Posted by jmcilhinney View Post
    Getting a return value is no more difficult. One thing I haven't mentioned is that the Invoke method is a function. If the method invoked by the delegate returns a value then that is propagated by the Invoke method. Let's use an example of getting the Text property of a TextBox. Following the steps laid out already we first create a method to do the job:
    CSharp Code:
    1. private string[] GetRichTextBoxLines()
    2. {
    3.     return this.rtbSongs.Lines;
    4. }
    Next we declare a matching delegate:
    CSharp Code:
    1. private delegate string[] GetRichTextBoxLinesInvoker();
    2.  
    3. private string[] GetRichTextBoxLines()
    4. {
    5.     return this.rtbSongs.Lines;
    6. }
    After that we test the InvokeRequired property:
    CSharp Code:
    1. private delegate string[] GetRichTextBoxLinesInvoker();
    2.  
    3. private string[] GetRichTextBoxLines()
    4. {
    5.     if (this.rtbSongs.InvokeRequired)
    6.     {
    7.  
    8.     }
    9.     else
    10.     {
    11.         return this.rtbSongs.Lines;
    12.     }
    13. }
    Finally we call the Invoke method and pass an instance of our delegate:
    CSharp Code:
    1. private delegate string[] GetRichTextBoxLinesInvoker();
    2.  
    3. private string[] GetRichTextBoxLines()
    4. {
    5.     if (this.rtbSongs.InvokeRequired)
    6.     {
    7.         return (string[])this.rtbSongs.Invoke(new GetRichTextBoxLinesInvoker(GetRichTextBoxLines));
    8.     }
    9.     else
    10.     {
    11.         return this.rtbSongs.Lines;
    12.     }
    13. }
    Let's clean that up a little so we only have one Return statement, which is widely considered to be best practice:
    CSharp Code:
    1. private delegate string[] GetRichTextBoxLinesInvoker();
    2.  
    3. private string[] GetRichTextBoxLines()
    4. {
    5.     string[] lines;
    6.  
    7.     if (this.rtbSongs.InvokeRequired)
    8.     {
    9.         lines = (string[])this.rtbSongs.Invoke(new GetRichTextBoxLinesInvoker(GetRichTextBoxLines));
    10.     }
    11.     else
    12.     {
    13.         lines = this.rtbSongs.Lines;
    14.     }
    15.  
    16.     return lines;
    17. }
    Notice that in this case we are actually returning the result of the Invoke method, which is the same value as was returned by the method that was invoked. This is how you get a value back onto your worker thread from the UI thread.

    Notice also that the return value from the invoke method must be cast as the appropriate type. Invoke can be used to invoke any method at all, so it could return any value at all. That means that its actual return type is Object. You must therefore cast each returned object as its actual type.

    Now to show that this method can be generalised to any control too, as well as combine the passing of parameters and returning a value, here's an extended example based on what we've already seen:
    CSharp Code:
    1. private delegate string[] GetTextBoxLinesInvoker(TextBoxBase ctl);
    2.  
    3. private string[] GetTextBoxLines(TextBoxBase ctl)
    4. {
    5.     string[] lines;
    6.  
    7.     if (ctl.InvokeRequired)
    8.     {
    9.         lines = (string[])ctl.Invoke(new GetTextBoxLinesInvoker(GetTextBoxLines),
    10.                                      ctl);
    11.     }
    12.     else
    13.     {
    14.         lines = ctl.Lines;
    15.     }
    16.  
    17.     return lines;
    18. }

  7. #7

    Thread Starter
    Frenzied Member
    Join Date
    Jan 2008
    Posts
    1,754

    Re: Invoke RichTextBox From Another Thread

    Thank you.

    I am getting this error message:
    Object of type 'System.String' cannot be converted to type 'System.String[]'.
    I don't see where I am converting a String to String array.. I am using strictly string arrays.

    Here is the code:
    Code:
    private delegate void SetRtbSongsDelegate(string[] newLines);
            private void SetRtbSongs(string[] newLines)
            {
                if (this.rtbSongs.InvokeRequired)
                {
                    // This is a worker thread so delegate the task.
                    this.rtbSongs.Invoke(new SetRtbSongsDelegate(this.SetRtbSongs), newLines);
                }
                else
                {
                    // This is the UI thread so perform the task.
                    this.rtbSongs.Lines = newLines;
                }
            }
    This is the line with the error:
    Code:
     this.rtbSongs.Invoke(new SetRtbSongsDelegate(this.SetRtbSongs), newLines);
    I am calling this like so:
    Code:
    SetRtbSongs(new string[1] { "" });

  8. #8
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,297

    Re: Invoke RichTextBox From Another Thread

    The problem is the fact that Invoke is declared such that it takes a delegate and then a paramarray of arguments for the method being invoked. Your string array is being interpreted as multiple individual arguments rather than a single array argument. Try casting the array as type Object to force it to be interpreted as a single argument:
    Code:
    this.rtbSongs.Invoke(new SetRtbSongsDelegate(this.SetRtbSongs), (object)newLines);

  9. #9

    Thread Starter
    Frenzied Member
    Join Date
    Jan 2008
    Posts
    1,754

    Re: [RESOLVED] Invoke RichTextBox From Another Thread

    It works!

    Thanks & Resolved

    -Also your explanations of cross-threading and invoking are excellent!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width