等待剪贴板文本更改(错误)

发布于 2024-11-10 13:21:39 字数 714 浏览 3 评论 0原文

我试图检测剪贴板数据的每次变化。因此,我设置了一个计时器并让它不断检查 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();
}

运行时出现以下错误:

在进行 OLE 调用之前,当前线程必须设置为单线程单元 (STA) 模式。

有谁知道为什么?

I'm trying to detect every time the clipboard data changes. And so, I set a timer and have it continuously check Clipboard.GetText() for changes.

I'm using the following code:

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();
}

I get the following error when it runs:

Current thread must be set to singlethread apartment (STA) mode before OLE calls can be made.

Does anyone know why?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

空宴 2024-11-17 13:21:40

您的方法访问 Clipboard 类,这是一个 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

我认为本文将为您提供一些有关如何更好地监视剪贴板的提示,从而避免此问题。虽然知道错误发生的原因仍然很好,但有更好的方法来完成此任务。

Your method accesses the Clipboard class, which is an OLE call that needs the caller to be in STA mode. Most likely the issue here is with your timer, which operates on a different thread. Here is a link that will help you out with more information about this:

http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/2411f889-8e30-4a6d-9e28-8a46e66c0fdb/

Also, here is a link to a full article on how to monitor the clipboard by tapping into the Windows events:

http://www.radsoftware.com.au/articles/clipboardmonitor.aspx

I think this article will give you some tips on how better to monitor the clipboard and thus you will avoid this issue. While it is still good to know why the error occurred, there is a better way for this task to be accomplished.

落花浅忆 2024-11-17 13:21:40

用计时器轮询剪贴板是非常糟糕的做法。剪贴板是共享资源,您将干扰正在监视剪贴板的其他应用程序(通过适当的剪贴板通知,即遵循规则)。无论用户尝试做什么,你都会发生冲突。例如,当用户尝试将数据复制到剪贴板,并且您已在轮询循环中打开它来检查它时,他会收到“无法打开剪贴板”错误或崩溃。请阅读 MSDN 中的剪贴板查看器:http:// /msdn.microsoft.com/en-us/library/ff468802(v=VS.85).aspx

Polling the clipboard with a timer is very bad practice. The clipboard is a shared resource, and you'll be interfering with other apps that are monitoring the clipboard (via proper clipboard notification, i.e. following the rules). And you'll be colliding with whatever the user is trying to do. For example, when the user attempts to copy data to the clipboard, and you have opened it in your polling loop to examine it, he'll get "cannot open clipboard" errors or crashes. Please read up on clipboard viewers in MSDN: http://msdn.microsoft.com/en-us/library/ff468802(v=VS.85).aspx

心不设防 2024-11-17 13:21:40

它基本上是任何托管 Windows GUI 应用程序的线程模型。运行与 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 的麻烦。

It's the threading model of basically any managed Windows GUI application. The thread that is running the code ergo interfacing with the UI thread must be the one and the same. If you maintain the SynchronizationContext of your start up path some where (you can put this in a static varible) you can post messages to it. Those messages will end up executing on the correct thread and you'll not get this error.

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();
    }
}

So, basically, when you are working with different threads (i.e. timers and what not) you need to remeber that the original start up thread is special (given that it's an STA thread). In order to invoke methods on objects that belong to that special thread you go through the SynchronizationContext which I've provided as a static member for my App class.

You might also wanna think about using a timer that actually dispatches to the main UI thread, then you wouldn't have to go trough the hassle of posting to the SynchronizationContext yourself.

真心难拥有 2024-11-17 13:21:40

对此不太确定,但您是否尝试过调用文本更改?我遇到了完全相同的错误(尽管在非常不同的情况下)并调用更改控件属性的方法解决了该错误。

我创建了一个带有字符串参数的委托:

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 线程以外的线程上的控件属性会导致问题。抱歉,如果这与您正在尝试的内容不符。

Not entirely sure with this but have you tried invoking the changing of text? I had the exact same error (although in a very different scenario) and invoking a method to change a control property solved it.

I created a delegate with a string parameter:

public delegate void TextBoxChangeDelegate(string text);

Then a method that will do the actual changing:

void TextBoxChange(string text)
{
   MyTextBox.Text = text;
}

Then I invoke this method in my thread process (and in your case, the timer event):

public void ThreadService()
{
  while(Running)
  {
    Invoke(new TextBoxChangeDelegate(TextBoxChange), new object[] { "New Value: "+ strNewValue });
  }

}

This was in WinForms. It was back when I knew for the first time that changing control properties on a thread other than the UI thread causes problems. Sorry if this isn't even close to what you're trying.

雪化雨蝶 2024-11-17 13:21:40

这是因为您不能在线程委托中使用 Windows 控件,基本上计时器是一个线程并传递使用 Windows 控件的委托会产生问题。
检查这是否有帮助
http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/2411f889-8e30-4a6d-9e28-8a46e66c0fdb/

Its because you can not use windows control in a thread delegate, basically timer is a thread and passing a delegate which using windows control is creating a problem.
check if this helps
http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/2411f889-8e30-4a6d-9e28-8a46e66c0fdb/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文