新手到c#这里,第一次处理事件处理程序。我正在编写的程序的一个步骤涉及每次在特定位置创建文件时更改剪贴板。这是我到目前为止所提出的:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;
using System.Windows.Forms;
namespace ConsoleApplication1
{
class Program
{
[STAThread]
public static void Main()
{
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = @"C:\Input\";
watcher.Filter = "*.csv";
watcher.Created += new FileSystemEventHandler(ProcessFile);
watcher.EnableRaisingEvents = true;
Console.ReadLine();
}
public static void ProcessFile(object source, FileSystemEventArgs e)
{
try
{
Clipboard.SetText("text");
}
catch (Exception exc)
{
Console.WriteLine(exc);
Console.ReadKey();
}
}
}
}
抛出异常,当前线程不处于STA模式,需要在Main方法中标记,但我相信我这样做了。如何在此更改剪贴板?
答案 0 :(得分:1)
问题是FileSystemWatcher
将在单独的线程上触发事件。您需要做一些事情,以便剪贴板操作发生在与Main
方法相同的线程中。
方法#1 :使用Application.Run
,即使您不使用WinForms。这样做是在主线程上旋转一个循环,等待事件。像这样:
static Form InvokerForm;
public static void Main()
{
InvokerForm = new Form();
var dummy = InvokerForm.Handle; // form handle creation is lazy; force it to happen
var watcher = new FileSystemWatcher();
watcher.SynchronizingObject = InvokerForm;
watcher.Path = @"C:\Input\";
watcher.Filter = "*.csv";
watcher.Created += new FileSystemEventHandler(ProcessFile);
watcher.EnableRaisingEvents = true;
Application.Run();
}
这告诉观察者在你创建的那个(不可见)表单上调用Invoke
,将你的处理程序作为参数传递。这基本上将它排队等待以后调用。与此同时,Application.Run
位于主线程上,旋转循环等待这种情况发生。当它注意到它时,它继续并在正确的线程上调用ProcessFile
。
方法#2 :如果这看起来太hacky,那是因为它有点。 “正确”的方法是使用自定义SynchronizingObject
。不幸的是,似乎没有一个内置,但有一篇文章describing how to create a delegate queue实现了ISynchronizeInvoke
。
这种方法的净效果是相同的:你最终会在主线程上有一些东西,等待调用请求,然后执行它们。只有这次你才能编写所有内部代码,同时使程序在系统资源使用方面更加精简。