我想写一个截图应用程序抓取屏幕截图,将其保存到文件中,使用该文件打开Paint.NET,然后在用户完成在Paint.NET中编辑文件时将编辑后的文件上传到服务
我有其他的东西被覆盖。如何在Paint.NET中检测图像何时完成编辑?
我正在使用.NET 3.5,C#。
我可以使用FileSystemWatcher来检测特定文件中的更改。但是第一次更改文件并不一定表明Paint.NET已完成。我可以等待Paint.NET退出 - 我想通过检查Windows中的进程列表并检测Paint.NET何时不再存在。但是用户可能在没有实际关闭Paint.NET的情况下完成编辑文件。
如果我必须告诉用户关闭Paint.NET,以表示该文件已准备好上传,我想我可以这样做。但我希望避免这种额外的要求。
如果Paint.NET在编辑时将文件打开以供阅读,那么我想我可以尝试观察那个。但是怎么样?也许通过轮询,尝试使用FileShare.None打开文件。
有更好的方法吗?
编辑 - 不,Paint.NET不会保持文件打开,甚至不读取。我可以打开一个没有问题的FileShare.None图像文件,即使它正在由Paint.NET显示/编辑。所以这个想法是行不通的。
Paint.NET是否有Remoting接口,我可以在其中查询它已打开的文件?这符合我的目的。
答案 0 :(得分:0)
不幸的是,没有更好的方法。编辑附件时,Microsoft Outlook等应用程序也存在同样的问题。您可以尝试通过采用上述方法进行最佳猜测。
例如,当您的应用程序在炮轰到Paint.NET(或者它们关联的任何编辑器)后再次变为活动状态时,您可以检查文件是否已更改,如果已完成则可能会提示。如果该过程关闭,您可以使用它作为一个非常明确的标志,表明它们已完成并跳过提示。如果文件系统观察程序检测到更改,则可以将这些更改排队,直到Paint.NET不再处于活动状态等等。
但是许多应用程序在编辑文件时不会对文件进行任何锁定。我很确定Paint.NET没有。像Office那样的应用程序可能就是为什么从Outlook编辑Word / Excel附件比纯文本文件更可靠的原因。
答案 1 :(得分:0)
稍微摆弄一下,我认为UI Automation会满足。使用.NET 3.0中新增的System.Windows.Automation类,我可以查询机器上其他Windows的内容,并且可以找到给定进程ID的窗口。
这是一个问题我没有对此进行过多次测试,但是,此代码似乎适用于我的目的:
public void Run()
{
var shortFileName = Path.GetFileName(_filename);
System.Console.WriteLine("Waiting for PDN to finish with {0}", shortFileName);
var s= from p in Process.GetProcesses()
where p.ProcessName.Contains("PaintDotNet.exe")
select p;
if (s.Count()==0)
{
System.Console.WriteLine("PDN is not running.");
return;
}
var process = s.First();
var window = AutomationElement.RootElement.FindChildByProcessId(process.Id);
string name =
window.GetCurrentPropertyValue(AutomationElement.NameProperty) as string;
if (!name.StartsWith(shortFileName))
{
System.Console.WriteLine("PDN appears to NOT be editing the file.");
}
else
{
try
{
int cycles = 0;
do
{
System.Threading.Thread.Sleep(800);
name = window.GetCurrentPropertyValue(AutomationElement.NameProperty) as string;
if (!name.StartsWith(shortFileName)) break;
cycles++;
System.Console.Write(".");
} while (cycles < 24);
if (!name.StartsWith(shortFileName))
System.Console.WriteLine("PDN is done.");
else
System.Console.WriteLine("Timeout.");
}
catch (ElementNotAvailableException)
{
System.Console.WriteLine("PDN has exited.");
}
}
}
FindChildByProcessId
方法是this blog post的扩展方法。它看起来像这样:
public static class AutomationExtensions
{
public static AutomationElement FindChildByProcessId(this AutomationElement element, int pid)
{
var cond = new PropertyCondition(AutomationElement.ProcessIdProperty, pid);
var result = element.FindChildByCondition(cond);
return result;
}
public static AutomationElement FindChildByCondition(this AutomationElement element, Condition cond)
{
var result = element.FindFirst(TreeScope.Children, cond);
return result;
}
}
这似乎有点不正统,但是,它只是有效。最棘手的部分是时间 - 你需要等待足够长的时间让应用程序启动,这可能是1秒或者可能是7秒。然后尝试使用UIAutomation类附加到它。