【发布时间】:2017-07-22 09:35:38
【问题描述】:
我想创建一个简单的“钢琴”应用程序,我可以在 UI 未被阻塞时按下按钮。
private void Form1_Load(object sender, EventArgs e)
{
Thread t = new Thread(() => keyboard());
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
public async void keyboard()
{
while(true)
{
if (Keyboard.IsKeyDown(Key.A))
{
btn_A_firstDo.BeginInvoke((Action)(() => btn_A_firstDo.Enabled = false));
//Play some music here...
await Task.Delay(1000);
btn_A_firstDo.BeginInvoke((Action)(() => btn_A_firstDo.Enabled = true));
}
}
}
我遇到了一个错误,我无法找到解决方案: “调用线程必须是 STA,因为很多 UI 组件都需要这个。” 我在这部分代码中遇到了这个错误:
if(Keyboard.IsKeyDown(Key.A))
尽管我对此进行了搜索,但我仍然没有完全理解这个错误。 我的问题如下:
- 如何解决此错误?是什么原因造成的?
- 我认为我没有正确使用
await。 例如,我想在不阻塞 UI 的情况下同时按下 2 个键。 如何解决? - 有什么方法可以让我的代码更优雅吗?
编辑:
我已经弄清楚了有效的代码:
(也在订阅事件KeyDown,示例将显示..)
public async void keyboard(Key key)
{
await Task.Run(() => {
this.BeginInvoke((Action) (() => {
btn_A_firstDo.Enabled = false;
// Play some music..
}));
Thread.Sleep(200);
this.BeginInvoke((Action) (() => {
btn_A_firstDo.Enabled = true;
}));
});
}
订阅事件KeyDown:
private void Piano_Load(object sender, EventArgs e)
{
this.KeyPreview = true;
this.KeyDown += SubKeyDown; // Deligate this event.
}
// Subscribing to event.
void SubKeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
switch(e.KeyCode)
{
case Keys.A:
keyboard(Key.A);
break;
// Continue with the cases...
default:
break;
}
}
【问题讨论】:
-
可能是 3 的答案:您应该订阅事件而不是运行循环来检查是否已按下某个键。
-
或者如果在这种情况下没有任何合适的事件,请使用
Timer。 -
主要问题呢?我该如何解决?
标签: c# winforms async-await