我想创建一个简单的“钢琴”应用程序,我可以在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
。
我想要例如并行按2个键而不阻止UI。
如何解决这个问题? 修改
我已经找到了有效的代码:
(同时致力于订阅活动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;
}
}
答案 0 :(得分:1)
1.我如何解决此错误?是什么导致了这个?
尽管设置了线程单元状态,但是你得到了异常,因为你使用await
,第二次通过你的循环你不再在你最初开始的线程中执行。延续以及之后的每个延续都是在线程池线程中执行的。您的原始帖子已经退出。
2.我不认为我正确使用了等待。我想要例如并行按2个键而不阻止UI。如何解决?
在您的问题中没有足够的背景知道答案可能是什么。您显示的涉及await
的代码似乎负责在您播放某些音乐时播放用户界面中的某些Button
对象"。如果你要编写一个看起来类似于这三个语句的UI线程调用的方法,那么这可以很容易地完成。例如:
private async Task PlayMusicA()
{
btn_A_firstDo.Enabled = false;
//Play some music here...
await Task.Delay(1000);
btn_A_firstDo.Enabled = true;
}
您可以在例如Click
事件处理程序中调用它:
private async void btn_A_firstDo_Click(object sender, EventArgs e)
{
await PlayMusicA();
}
3.有什么方法可以让我的代码更优雅吗?
对于处理键输入,您的表单监视键输入并响应键输入事件更有意义,而不是像您在此处尝试那样轮询键盘。
同样,您的问题含糊不清,因此不清楚您需要做什么,但您可能会发现an answer I wrote previously讨论如何跟踪某个键是否被按下(即&#34 ;向上"或"向下")以便在密钥关闭时可以应用某些连续行为。
另一方面,如果您只关心初始按键,并且不需要知道密钥何时被释放,那么其他答案将无法帮助而且不是需要。您只需要处理表单中的键输入。不幸的是,这是一个相当复杂的主题,因为有很多变化。表单可以有孩子也需要键输入,因此有几个不同的事件和方法可以覆盖以接收键输入,每个事件和方法都有微妙的不同行为。在单个Stack Overflow答案中描述所有内容实际上过于宽泛。
相反,您应该看一下可用的内容。在一个非常简单的场景中,在表单类中订阅KeyPress
事件可能就足够了。如果您的表单包含通常会收到键输入的其他控件,但您希望能够响应特定键,则可能需要使用PreviewKeyDown
事件(与KeyPress
略有不同... KeyPress
事件报告字符输入,在Windows翻译特定键后,PreviewKeyDown
告诉您键盘上的哪个物理键被按下了。如果您的场景比那些适用于其中任何一个场景的场景更复杂,您可能会发现自己必须覆盖表单中的Process...
个关键方法之一。
同样,您的问题中的信息不足以确定哪种方法最适合您。你应该使用上面的建议来尝试使某些东西发挥作用,然后如果你仍然需要帮助,花一些时间来做一个好的Minimal, Complete, and Verifiable code example,清楚地显示你已经尝试过的东西,并准确地解释 代码的作用以及您希望它做什么。