Click here to Skip to main content
15,885,760 members
Articles / Programming Languages / C#

Component Manipulator from separate threads

Rate me:
Please Sign up or sign in to vote.
4.64/5 (7 votes)
26 Aug 2009CPOL1 min read 20.5K   120   17   5
An easy to use form component manipulator from separate threads.

Introduction

When using multiple threads in C# and you want to modify a control on the form, you receive an error like this:

Cross-thread operation not valid: Control 'XXX' accessed from 
       a thread other than the thread it was created on.

To resolve this problem, you have to create a delegate for each component you want to modify, or, if you want to separately modify more properties, more delegates. If you want to modify many components, you end up creating a lot of delegates and delegate methods.

Background

Creating a simple delegate

Declaring the delegate:

C#
private delegate void updateFileLabel(string str, int index);

Declaring the method:

C#
private void updateLabel(string str, int index)
{
    if (label3.InvokeRequired)
    {
        updateFileLabel d = new updateFileLabel(updateLabel);
        this.Invoke(d, new object[] { str, index });
    }
    else
    {
        label3.Text = "Proccessing: " + 
          str.Substring(0, Math.Min(5,str.LastIndexOf("\\"))) + 
          "..." + str.Substring(str.LastIndexOf("\\"));
    }
}

And if you want to manipulate many components and more than one property, there is a lot of code to write. The solution: Component Manipulator. To access the different properties, the class uses GetType() that is defined for any object, and from there, using Reflection, everything is simple.

Using the code

The use of the code is simple. All the methods are static. There are three different methods to manipulate the components.

GetComponentProperty

C#
public static object GetComponentProperty(Control component, string query)
{
    if (component == null) { return null; }
    if (component.InvokeRequired)
    {
        GetComponentPropertyDelegate delegateObject = 
            new GetComponentPropertyDelegate(GetComponentProperty);
        return component.Invoke(delegateObject, new object[] { component, query });
    }
    else
    {
        object obj = GetQueryObject(component, ref query);
        Property property = GetProperty(query);
        obj = GetObjectPropertyValue(obj, property.name);
        if (obj == null) { return null; }
        if (property.index != null)
        {
            obj = GetItemFromArray(obj, property.index);
        }
        return obj;
    }
}

This method uses a delegate:

C#
protected delegate object GetComponentPropertyDelegate(Control component, string query);

To use this method, you write:

C#
bool isChecked = (bool)ComponentManipulator.GetComponentProperty(listView1, 
                      "Items[" + item + "].Checked");
string fileName = ComponentManipulator.GetComponentProperty(listView1, 
                      "Items[" + item + "].Text") as string;

The query parameter is used to access the property you want.

SetComponentProperty

C#
public static void SetComponentProperty(Control component, string query, object value)
{
    if (component == null || value == null) { return; }
    if (component.InvokeRequired)
    {
        SetComponentPropertyDelegate delegateObject = 
                    new SetComponentPropertyDelegate(SetComponentProperty);
        component.Invoke(delegateObject, new object[] { component, query, value });
    }
    else
    {
        object obj = GetQueryObject(component, ref query);
        Property property = GetProperty(query);
        if (property.index != null)
        {
            obj = GetObjectPropertyValue(obj, property.name);
            if (obj == null) { return; }
            SetItemFromArray(obj, property.index, value);
        }
        else
        {
            SetObjectPropertyValue(obj, query, value);
        }
    }
}

This method uses a delegate:

C#
protected delegate void SetComponentPropertyDelegate(Control component, 
                        string query, object value);

To use this method, you write:

C#
ComponentManipulator.SetComponentProperty(listView1, 
   "Items[" + item + "].SubItems[1].Text", 
   "Not selected for encoding");

The query parameter is used to access the property you want. The value parameter is the value to set for the property you access with the query.

CallComponentMethod

C#
public static void CallComponentMethod(Control component, string query, object [] parameters)
{
    if (component == null) { return; }
    if (component.InvokeRequired)
    {
        CallComponentMethodDelegate delegateObject = 
                  new CallComponentMethodDelegate(CallComponentMethod);
        component.Invoke(delegateObject, new object[] { component, query });
    }
    else
    {
        object obj = GetQueryObject(component, ref query);
        Property property = GetProperty(query);
        if (property.index == null)
        {
            CallObjectMethod(obj, query, parameters);
        }
    }
}

This method uses a delegate:

C#
protected delegate void CallComponentMethodDelegate(Control component, 
                                  string query, object [] parameters);

To use this method, you write:

C#
ComponentManipulator.CallComponentMethod(listView1, 
         "Items[" + item + "].SubItems[1].ResetStyle");

Note: The method must not have parentheses ().

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Ipsos Group
Romania Romania
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralOvercomplicated solution Pin
GeorgeTheElder26-Aug-09 17:34
GeorgeTheElder26-Aug-09 17:34 
AnswerRe: Overcomplicated solution Pin
badicuady27-Aug-09 4:43
badicuady27-Aug-09 4:43 
GeneralRe: Overcomplicated solution Pin
TobiasP10-Sep-09 4:07
TobiasP10-Sep-09 4:07 
GeneralVery good :) Pin
Anthony Daly26-Aug-09 3:19
Anthony Daly26-Aug-09 3:19 
GeneralRe: Very good :) Pin
dequadin26-Aug-09 4:11
dequadin26-Aug-09 4:11 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.