Home > other >  How to use delegate?
How to use delegate?

Time:07-29

I use delegate in different threads.

This is work:

delegate void AppendTextDelegate(string text);

 public void appendTextData(string text)
 {
        if (richBox1.InvokeRequired)
        {
            richBox1.Invoke(new AppendTextDelegate(appendTextData), new object[] { text           });
        }
        else
        {
            richBox1.AppendText(text);
        }
    }

This is work too:

delegate void ChangeValDelegate(int value);

progressBar1.Invoke(new ChangeValDelegate((s) => progressBar1.Value = s), 0);

This is not work:

delegate void ClearDelegate();

listView.Invoke(new ClearDelegate()); <-- "Does not contain a constructor that takes 0 arguments"

CodePudding user response:

I think you are creating lots of delegates to work with your controls. Also, you are using each control (listview, richtextbox...) when you can use only one of them, for example, your form.

The problem here is that you must work with your controls in the same thread in which they was created. You use InvokeRequired to check this and run the code in other thread (main thread) when you are running code in a different thread.

Usually, all your controls and forms are created in the main thread, so you can check only with one of your controls to know when it's safe to access to the controls.

Here you have a way to do the same in a more compact and simple way. First, add this field to your form:

private static SynchronizationContext Context;

And set it's value in your form contructor:

Context = SynchronizationContext.Current;

SynchronizationContext.Current it's different in differents contexts but in the form contructor you know that the context it's the Form context (your main thread). So, we save in Context the context in which we can access to the form (and all it's controls).

Add this method to simplify the work with controls:

private static void RunInMainThread(Action operation)
{
    if (Context != SynchronizationContext.Current)
    {
        Context.Post(o =>
        {
            try
            {
                operation();
            }
            catch (ObjectDisposedException)
            {
            }
        }, null);
    }
    else
    {
        operation();
    }
}

It's similar to InvokeRequired but with SynchronizationContext. If you are in the right place (same context of your form), simply run the action. In other case, run the action in the form context. Here you can see that it's done using Post. In this way, you avoid deadlocks and accept that the code may run with a bit delay (because is enqueued).

And why an Action? because you can run anything using the action, leaving the parameters outside of the method invocation. You don't need lots of methods with different parameters to control any access to your controls.

For example:

public void appendTextData(string text)
{
    RunInMainThread(() =>
    {
        richBox1.AppendText(text);
    });

    // Beeing a single line, you can compact the code
    //RunInMainThread(() => richBox1.AppendText(text));
}

You run your AppendText with the text parameter, but you don't need this parameter in your RunInMainThread method.

Another example, to set progress bar to start and clear the listview:

RunInMainThread(() =>
{
    progressBar1.Value = 0;
    listview.Clear();
});

And about the delegates: they are like a contract, like an interface. A delegate hasn't code, only tell you about the arguments... but without code.

In your code:

progressBar1.Invoke(
    new ChangeValDelegate(
        (s) => progressBar1.Value = s), 0);

You are running an implementation that match with your delegate (return void and get an integer as a parameter).

Is like:

var d = new ChangeValDelegate(OnChangeValDelegate);
BeginInvoke(d, new object[] { 0 });

Having:

public void OnChangeValDelegate(int value)
{
    progressBar1.Value = value;
}

As you see, you need an implementation. Here:

listView.Invoke(
    new ClearDelegate(/* NO IMPLEMENTATION */));

You need the code (matching your delegate) that clear the listview.

  • Related