-1

I've been trying to modify some GUI elements before/after a TCP connection that i'm trying to execute synchronously and assynchronously.

public async void ConnectAsync(String h, String p, String n)
{
    if (connected)
        return;

    try
    {
        hostname = new HostName(h);
        port = p;
        nickname = n;

        await sock.ConnectAsync(hostname, port);

        connected = true;
        if (Connected != null)
            Connected(this, EventArgs.Empty);
    }
    catch (Exception e)
    {
        sock.Dispose();
        hostname = null;
        port = null;
        nickname = null;

        if (ConnectionFailed != null)
            ConnectionFailed(this, EventArgs.Empty);
    }
}

This method above is called by the GUI class (code below):

private void ConnectButtonClicked(object sender, RoutedEventArgs e)
{
    string nickname;

    if (Bar.Visibility == Windows.UI.Xaml.Visibility.Visible)
        Bar.Visibility = Windows.UI.Xaml.Visibility.Collapsed;

    if (Status.Visibility == Windows.UI.Xaml.Visibility.Collapsed)
        Status.Visibility = Windows.UI.Xaml.Visibility.Visible;

    qc.ConnectionFailed += new ConnectionFailedEventHandler(ConnectionFailedEventHandler);
    qc.Connected += new ConnectedEventHandler(ConnectedEventHandler);

    nickname = Nickname.Text;

    /* HERE */
    Task.Run(() => qc.ConnectAsync("irc.quakenet.org", "6667", nickname));

    updateStatus("Connecting...");
    ConnectButton.IsEnabled = false;
    Nickname.IsEnabled = false;
    ProgLanguages.IsEnabled = false;
}

See that the method raises two different events..

If i call this method like this code, with Task.Run(..), those events are raised and when they are handled, the code tries to modify the GUI by this thread and an exception is thrown.

If i call the method without the Task.Run(..), the GUI freezes and i can't modify the elements to show that it's "Connecting" and something like that.

Any idea how can i do this?

Ramon Saraiva
  • 518
  • 1
  • 5
  • 14
  • 1
    have you tried having 'await' in front of your Task.Run so it allows background task to finish (and not block UI). YOu need to add async to that bottom method signature though and make it return Task – Lotok May 06 '13 at 22:48
  • What is the exception you're getting? is it `Cross-thread operation not valid`? – Arian Motamedi May 06 '13 at 22:51
  • Agree with @James. Your better desing would be to await ConnectAsync. And return result that indicates connection status. No need for events. – Jurica Smircic May 06 '13 at 22:54

2 Answers2

2

First, avoid async void, so change ConnectAsync to return Task.

Then, your event handler can just do await qc.ConnectAsync(...) and there's no need for Task.Run at all.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
-1

You need to use Control.Invoke()

I just replied to the same problem here: Background worker report string from a method

you need to wrap you call to any UI control by a call to Control.Invoke()

The rule is: any UI control can't be accessed by another thread than the one used to create it. So you need to "ask" the UI thread to execute the code that update your UI control. It's the job of the Invoke method (inherited from the Control class)

Community
  • 1
  • 1
Fabske
  • 2,106
  • 18
  • 33