ant2009
ant2009

Reputation: 22656

Invoke delegate for many controls

C# 2008 SP1

The function below will be called from another thread. So the control themselves will have to be invoked so that the correct thread that created them can change the properties.

However, as I have many controls that need to be updated. I don't really want to write all those delegates for each one. I have done one below. However, I am thinking that is a lot of code. Is there anyway to shorten this?

Many thanks,

public void SetIdleState(string callStatusMsg)
    {
        this.btnCallAnswer.Text = CATWinSIP_MsgStrings.Call;
        this.btnEndCallReject.Text = CATWinSIP_MsgStrings.EndCall;
        this.btnHoldUnhold.Text = CATWinSIP_MsgStrings.Hold;

        this.btnCallAnswer.Enabled = true;
        this.btnRedial.Enabled = true;
        this.btnEndCallReject.Enabled = false;
        this.btnHoldUnhold.Enabled = false;

        if (this.statusDisplay1.InvokeRequired)
        {
            statusDisplay1.Invoke(new UpdateCallStatusDelegate(this.UpdateCallStatus), callStatusMsg);      
        }
        else
        {
           this.statusDisplay1.CallStatus = callStatusMsg;
        }
    }      

    // Delegate for marshalling the call on the correct thread.
    private delegate void UpdateCallStatusDelegate(string callStatusMsg);
    private void UpdateCallStatus(string callStatusMsg)
    {
        this.statusDisplay1.CallStatus = callStatusMsg;
    }

Upvotes: 2

Views: 2539

Answers (4)

ant2009
ant2009

Reputation: 22656

I found the best way to do this. And converted my code to this.

Hope this helps someone else.

 // Delegate for marshalling the call on the correct thread.
    private delegate void SetIdleStateDelegate(string callStatusMsg);

    // Set object back to idle state.
    public void SetIdleState(string callStatusMsg)
    {
        if (this.InvokeRequired)
        {
            this.Invoke(new SetIdleStateDelegate(SetIdleState), callStatusMsg);
        }
        else
        {
            this.btnCallAnswer.Text = CATWinSIP_MsgStrings.Call;
            this.btnEndCallReject.Text = CATWinSIP_MsgStrings.EndCall;
            this.btnHoldUnhold.Text = CATWinSIP_MsgStrings.Hold;

            this.btnCallAnswer.Enabled = true;
            this.btnRedial.Enabled = true;
            this.btnEndCallReject.Enabled = false;
            this.btnHoldUnhold.Enabled = false;
        }           
    }      

Upvotes: 0

John Simons
John Simons

Reputation: 4288

Here is what I've done in a previous project:

I wrote a helper static class.

public static class WorkbenchService
{    
    private static SynchronizationContext uiContext;
static WorkbenchService()
{
    uiContext = WindowsFormsSynchronizationContext.Current;
}

/// <summary>
    /// Makes a call GUI threadSafe. WARNING: This method waits for the result of the operation, which can result in a dead-lock when the main thread waits for this thread to exit!
    /// </summary>
    public static void SafeThreadCall(SendOrPostCallback d, object state)
    {
        uiContext.Send(d, state);
    }
    /// <summary>
    /// Makes a call GUI thread safe without waiting for the returned value.
    /// </summary>
    public static void SafeThreadAsyncCall(SendOrPostCallback d, object state)
    {
        uiContext.Post(d, state);
    }
}

And then I use it like:

    WorkbenchService.SafeThreadAsyncCall(delegate                                                   {
    this.statusDisplay1.CallStatus = "Blah";
    this.btnCallAnswer.Text = "hello there";
}, null);

Upvotes: 1

sipsorcery
sipsorcery

Reputation: 30734

I asked a similar question . The answer that was provided by Jon Skeet is the best approach I have come across. The relevant code is below.

Create a static helper method:

public static void InvokeIfNecessary(UIElement element, MethodInvoker action)
{
    if (element.Dispatcher.Thread != Thread.CurrentThread)
    {
        element.Dispatcher.Invoke(DispatcherPriority.Normal, action);
    }
    else
    {
        action();
    }
}

In your example you could use it as:

InvokeIfNecessary(statusDisplay1, delegate {statusDisplay1.CallStatus = callStatusMsg;});

Upvotes: 1

Sean Turner
Sean Turner

Reputation: 1178

How about something like:

Dispatcher.BeginInvoke(new DispatcherOperationCallback((param) =>

      {

           this.statusDisplay1.CallStatus = callStatusMsg;

          return null;

      }), DispatcherPriority.Background, new object[] { null });

    }

Upvotes: 1

Related Questions