每次剪贴板数据发生变化时,我都会尝试检测.所以,我设置了一个计时器,让它不断检查Clipboard.GetText()的变化.
我正在使用以下代码:
public void WaitForNewClipboardData()
{
//This is in WPF, Timer comes from System.Timers
Timer timer = new Timer(100);
timer.Elapsed += new ElapsedEventHandler(
delegate(object a, ElapsedEventArgs b){
if (Clipboard.GetText() != ClipBoardData)
{
SelectedText.Text = Clipboard.GetText();
ClipBoardData = Clipboard.GetText();
timer.Stop();
}
});
timer.Start();
}
运行时出现以下错误:
Current thread must be set to singlethread apartment (STA) mode before OLE calls can be made.
有谁知道为什么?
解决方法:
它是基本上任何托管Windows GUI应用程序的线程模型.运行代码ergo与UI线程连接的线程必须是同一个.如果您将启动路径的SynchronizationContext维护在某个位置(您可以将其置于静态变量中),则可以向其发布消息.这些消息将最终在正确的线程上执行,您将不会收到此错误.
public partial class App : Application
{
public static SynchronizationContext SynchronizationContext;
protected override void OnStartup(StartupEventArgs e)
{
// This is my preferred way of accessing the correct SynchronizationContext in a WPF app
SynchronizationContext = SynchronizationContext.Current;
base.OnStartup(e);
var mainWindow = MainWindow;
var t = new Thread(() => {
Thread.Sleep(3000);
SynchronizationContext.Post(state => {
mainWindow.Hide(); // this will not throw an exception
}, null);
mainWindow.Close(); // this will throw an exception
});
t.Start();
}
}
所以,基本上,当你使用不同的线程(即定时器和不是什么)时,你需要记住原始的启动线程是特殊的(假设它是一个STA线程).为了在属于该特殊线程的对象上调用方法,您将通过我作为App类的静态成员提供的SynchronizationContext.
您可能还想考虑使用实际调度到主UI线程的计时器,然后您不必自己去发布到SynchronizationContext的麻烦.