1
votes

I am new to developing with Windows forms applications and I have an issue I could do with some help / guidance on the best practice approach I should be taking.

Background:

I have an forms based application that needs to refresh every minute with data from a WCF service and then update the UI with the latest results in a List View control. I have this all working in principal but the application crashes intermittently and I need to resolve this. I have stripped out the main parts of the code below. The actual nuts and bolts are probably not required.

Code:

public partial class Form1 : Form
{
readonly MatchServiceReference.MatchServiceClient _client = new MatchServiceReference.MatchServiceClient();

public Form1()
    {
        _client.GetMMDataCompleted += new EventHandler<GetMMDataCompletedEventArgs>(_client_GetMMDataCompleted);
    }    

//Arm Timer
private void ArmTimer(object sender, EventArgs e)
    {
        aTimer = new Timer();

        aTimer.Elapsed += OnTimedEvent;

        aTimer.Interval = 60000;
        aTimer.Enabled = true;
    }

//Timer elapsed event
 private void OnTimedEvent(object source, ElapsedEventArgs e)
    {
        try
        {
            LoadMatches();

            if (LastUpdated.InvokeRequired)
            {
                LastUpdated.Invoke(new MethodInvoker(delegate { LastUpdated.Text = e.SignalTime.ToString(); }));
            }
        }
        catch (Exception exception)
        {

        }

    }

//Load matches
private void LoadMatches()
    {
        try
        {
            aTimer.Enabled = false;
            _client.GetMMDataAsync();
        }
        catch (Exception e)
        {
            //EventLog.WriteEntry("Application", e.InnerException.ToString(), EventLogEntryType.Error);
            aTimer.Enabled = true;
        }
    }

void _client_GetMMDataCompleted(object sender, GetMMDataCompletedEventArgs e)
    {
        if (e.Result != null)
        {

            var matches = e.Result;

            Debug.WriteLine("Matches received from service");

            if (!IsHandleCreated && !IsDisposed) return;

            // Invoke an anonymous method on the thread of the form.
            Invoke((MethodInvoker) delegate
                                       {
                                           try
                                           {
                                               LoadTheMonitorMatches(matches);
                                           }
                                           catch (Exception exception)
                                           {
                                               Debug.WriteLine("INNER EXCEPTION" + exception.InnerException);
                                               Debug.WriteLine("EXCEPTION MESSAGE" + exception.Message);
                                           }
                                       });
        }
        aTimer.Enabled = true;
    }
}

}

Exception:

The exception I am getting is as follows -

Exception Info: System.Reflection.TargetInvocationException Stack: at System.ComponentModel.AsyncCompletedEventArgs.RaiseExceptionIfNecessary() at MM.MatchServiceReference.GetMMDataCompletedEventArgs.get_Result() at MM.Form1._client_GetMMDataCompleted(System.Object, MM.MatchServiceReference.GetMMDataCompletedEventArgs) at MM.MatchServiceReference.MatchServiceClient.OnGetMMDataCompleted(System.Object) at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(System.Object) at System.Threading.ExecutionContext.runTryCode(System.Object) at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode, CleanupCode, System.Object) at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() at System.Threading.ThreadPoolWorkQueue.Dispatch() at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

Any help / advice with this would be greatly appreciated.

Cheers

2

2 Answers

1
votes

The line

  if (e.Result != null)

is actually calling the getter for result. Since the event args derive from AsyncCompletedEventArgs this can raise an error if the operation was cancelled or errored. Check the cancelled and error properties first before testing the result and you should be able to trap the problem.

From the docs: If the component's asynchronous worker code assigns an exception to the Error property or sets the Cancelled property to true, the property will raise an exception if a client tries to read its value.

2
votes

You're using the wrong timer. The System.Timers.Timer is intended to use on servers. For a Winform application you should use the System.Windows.Forms.Timer and add it as a control to your form. When you use it, the UI is responsive between timer ticks but when it goes to bring data, the UI will become irresponsive. If it is not good enough for you, you should use the BackgroundWorker.

If the problem is still there after using these components, ask the question again.