我一直在尝试在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会冻结,我无法修改元素以显示它是“正在连接”之类的东西。
知道我该怎么做?
答案 0 :(得分:2)
首先,请避开async void
,因此请更改ConnectAsync
以返回Task
。
然后,您的事件处理程序可以await qc.ConnectAsync(...)
,而且根本不需要Task.Run
。
答案 1 :(得分:-1)
您需要使用Control.Invoke()
我刚刚回答了同样的问题:Background worker report string from a method
您需要通过调用Control.Invoke()
来调用任何UI控件规则是:任何UI控件都不能被用于创建它的其他线程访问。因此,您需要“询问”UI线程以执行更新UI控件的代码。这是Invoke方法的工作(继承自Control类)