在异步方法中获取剪贴板文本
Get clipboard text in async method
我在通过异步方法获取剪贴板文本时遇到问题。因为它总是 returns 一个空值(虽然它不为空)。这是问题的简单演示:
private async void button_Click(object sender, EventArgs e)
{
string result = await Task<string>.Run(() =>
{
System.Threading.Thread.Sleep(3000);
return Clipboard.GetText(); //returns empty! (but clipboard is not empty)
});
MessageBox.Show(result);
}
我确定剪贴板不是空的。有什么解决办法?
这应该有效:
private static int counter;
private async void button1_Click(object sender, EventArgs e)
{
counter++;
button1.Text = counter.ToString();
// Solution 1 (preferred)
await LongOperation();
Debug.WriteLine("Solution 1 completed for counter " + counter);
// Solution 2 (use if LongOperation is CPU-bound)
var t = Task.Run(LongOperation);
await t;
Debug.WriteLine("Solution 2 completed for counter " + counter);
Debug.WriteLine(Clipboard.GetText());
}
private async Task LongOperation()
{
await Task.Delay(10000);
}
连续点击 button1 3 次。结果:
// Click 3 times in a row on the button. Result:
// After 10 seconds:
Solution 1 completed for counter 3
Solution 1 completed for counter 3
Solution 1 completed for counter 3
// After 10 more seconds:
Solution 2 completed for counter 3
<clipboard content>
Solution 2 completed for counter 3
<clipboard content>
Solution 2 completed for counter 3
<clipboard content>
它不起作用,因为剪贴板仅在 COM threading model (apartment)
为 STA
而您的 Task
公寓为 MTA
时才有效。
您不能更改任务的单元,但可以改用线程。线程有一个 SetApartmentState
方法。
STA and MTA explained here
但我找到了 a solution to create an STA Task !
诀窍是 运行 使用任务的 STA 线程:
public static Task<T> StartSTATask<T>(Func<T> func)
{
var tcs = new TaskCompletionSource<T>();
var thread = new Thread(() =>
{
try
{
var result = func();
tcs.SetResult(result);
}
catch (Exception e)
{
tcs.SetException(e);
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
return tcs.Task;
}
所以现在你可以让它像这样工作了:
private async void button1_Click(object sender, EventArgs e)
{
var result = await StartSTATask(() =>
{
Thread.Sleep(3000);
return Clipboard.GetText();
});
MessageBox.Show(result);
}
我在通过异步方法获取剪贴板文本时遇到问题。因为它总是 returns 一个空值(虽然它不为空)。这是问题的简单演示:
private async void button_Click(object sender, EventArgs e)
{
string result = await Task<string>.Run(() =>
{
System.Threading.Thread.Sleep(3000);
return Clipboard.GetText(); //returns empty! (but clipboard is not empty)
});
MessageBox.Show(result);
}
我确定剪贴板不是空的。有什么解决办法?
这应该有效:
private static int counter;
private async void button1_Click(object sender, EventArgs e)
{
counter++;
button1.Text = counter.ToString();
// Solution 1 (preferred)
await LongOperation();
Debug.WriteLine("Solution 1 completed for counter " + counter);
// Solution 2 (use if LongOperation is CPU-bound)
var t = Task.Run(LongOperation);
await t;
Debug.WriteLine("Solution 2 completed for counter " + counter);
Debug.WriteLine(Clipboard.GetText());
}
private async Task LongOperation()
{
await Task.Delay(10000);
}
连续点击 button1 3 次。结果:
// Click 3 times in a row on the button. Result:
// After 10 seconds:
Solution 1 completed for counter 3
Solution 1 completed for counter 3
Solution 1 completed for counter 3
// After 10 more seconds:
Solution 2 completed for counter 3
<clipboard content>
Solution 2 completed for counter 3
<clipboard content>
Solution 2 completed for counter 3
<clipboard content>
它不起作用,因为剪贴板仅在 COM threading model (apartment)
为 STA
而您的 Task
公寓为 MTA
时才有效。
您不能更改任务的单元,但可以改用线程。线程有一个 SetApartmentState
方法。
STA and MTA explained here
但我找到了 a solution to create an STA Task !
诀窍是 运行 使用任务的 STA 线程:
public static Task<T> StartSTATask<T>(Func<T> func)
{
var tcs = new TaskCompletionSource<T>();
var thread = new Thread(() =>
{
try
{
var result = func();
tcs.SetResult(result);
}
catch (Exception e)
{
tcs.SetException(e);
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
return tcs.Task;
}
所以现在你可以让它像这样工作了:
private async void button1_Click(object sender, EventArgs e)
{
var result = await StartSTATask(() =>
{
Thread.Sleep(3000);
return Clipboard.GetText();
});
MessageBox.Show(result);
}