-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
  • 488
  • 5
  • 14

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
  • 406,130
  • 70
  • 637
  • 767
-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,006
  • 17
  • 31