-1

我一直在尝试在尝试同步和异步执行的 TCP 连接之前/之后修改一些 GUI 元素。

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);
    }
}

上面的这个方法由 GUI 类调用(代码如下):

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;
}

看到该方法引发了两个不同的事件..

如果我使用 Task.Run(..) 像这段代码一样调用此方法,则会引发这些事件,并且在处理它们时,代码会尝试通过该线程修改 GUI 并引发异常。

如果我在没有 Task.Run(..) 的情况下调用该方法,GUI 将冻结,我无法修改元素以显示它是“正在连接”之类的东西。

知道我该怎么做吗?

4

2 回答 2

2

首先,避免async void,所以更改ConnectAsync为返回Task

然后,您的事件处理程序可以做await qc.ConnectAsync(...),根本不需要Task.Run

于 2013-05-06T22:56:26.743 回答
-1

您需要使用 Control.Invoke()

我刚刚在这里回答了同样的问题:Background worker report string from a method

您需要通过调用 Control.Invoke() 来包装对任何 UI 控件的调用

规则是:任何 UI 控件都不能被用于创建它的线程之外的另一个线程访问。所以你需要“询问” UI 线程来执行更新你的 UI 控件的代码。这是 Invoke 方法的工作(继承自 Control 类)

于 2013-05-06T22:48:15.600 回答