正在等待剪贴板文本更改(错误)
本文关键字:错误 在等待 剪贴板 文本 | 更新日期: 2023-09-27 17:57:52
我正在尝试检测剪贴板数据的每次更改。因此,我设置了一个计时器,让它不断地检查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();
}
当它运行时,我得到以下错误:
必须将当前线程设置为单线程单元(STA)模式,才能进行OLE调用。
有人知道为什么吗?
您的方法访问剪贴板类,这是一个OLE调用,需要调用方处于STA模式。这里的问题很可能是你的计时器,它在不同的线程上运行。这里有一个链接,可以帮助你了解更多信息:
http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/2411f889-8e30-4a6d-9e28-8a46e66c0fdb/
此外,这里有一个完整文章的链接,介绍如何通过点击Windows事件来监控剪贴板:
http://www.radsoftware.com.au/articles/clipboardmonitor.aspx
我认为这篇文章会给你一些关于如何更好地监控剪贴板的提示,从而避免这个问题。虽然知道错误发生的原因仍然很好,但有更好的方法可以完成这项任务。
使用计时器轮询剪贴板是非常糟糕的做法。剪贴板是一个共享资源,您将干扰正在监视剪贴板的其他应用程序(通过适当的剪贴板通知,即遵守规则)。你会与用户尝试做的任何事情发生冲突。例如,当用户试图将数据复制到剪贴板,而你在轮询循环中打开它进行检查时,他会收到"无法打开剪贴板"的错误或崩溃。请在MSDN中的剪贴板查看器上阅读:http://msdn.microsoft.com/en-us/library/ff468802(v=VS.85).aspx
它基本上是任何托管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线程)。为了在属于该特殊线程的对象上调用方法,您需要经过SynchronizationContext,我为App类提供了它作为静态成员。
您可能还想考虑使用一个实际调度到主UI线程的计时器,这样您就不必自己费力地发布到SynchronizationContext。
对此不完全确定,但您是否尝试过调用文本更改?我有完全相同的错误(尽管在一个非常不同的场景中),调用一个方法来更改控制属性解决了这个问题
我创建了一个带有字符串参数的委托:
public delegate void TextBoxChangeDelegate(string text);
然后是一种将进行实际更改的方法:
void TextBoxChange(string text)
{
MyTextBox.Text = text;
}
然后我在线程进程中调用这个方法(在您的情况下,调用计时器事件):
public void ThreadService()
{
while(Running)
{
Invoke(new TextBoxChangeDelegate(TextBoxChange), new object[] { "New Value: "+ strNewValue });
}
}
这是在WinForms中。当我第一次知道在UI线程以外的线程上更改控件属性会导致问题时,我就知道了。很抱歉,如果这甚至与你尝试的不接近。
因为不能在线程委托中使用windows控件,所以计时器基本上是一个线程,传递使用windows控件的委托会产生问题。检查这是否有帮助http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/2411f889-8e30-4a6d-9e28-8a46e66c0fdb/