.net - hvordan kan jeg vide, hvornår brugeren er færdig med at redigere en fil i Paint.NET?

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg vil skrive en screenshot-app, der tager et skærmbillede, gemmer det til en fil, åbner Paint.NET med den pågældende fil og uploader den redigerede fil til en tjeneste, når brugeren er færdig med at redigere filen i Paint.NET.


Jeg har de andre ting slags dækket. Hvordan kan jeg opdage, hvornår billedet er færdig med at blive redigeret i Paint.NET?


Jeg bruger .NET 3.5, C #.


Jeg kan bruge en FileSystemWatcher til at registrere ændringer i en bestemt fil. Men første gang en filændringer indikerer ikke nødvendigvis, at Paint.NET er færdig. Jeg kan vente på Paint.NET for at afslutte - jeg formoder at gennemgå listen over processer i Windows og opdage, hvornår Paint.NET ikke længere er der. Men en bruger kan måske afslutte redigering af en fil uden at lukke Paint.NET. [4]


Hvis jeg skal fortælle brugeren at lukke Paint.NET for at signalere, at filen er klar til upload, antager jeg, at jeg kunne gøre det. Men jeg håber at undgå den slags ekstra krav.


Hvis Paint.NET har en fil åben for læsning, mens den redigeres, så antager jeg, at jeg kunne prøve at se på det . Men hvordan? Måske ved afstemning, forsøger at åbne filen med FileShare.None. [5]


Er der en bedre måde?





REDIGER - nej, Paint.NET holder ikke filen åben, ikke engang til læsning. Jeg kan ikke åbne en billedfil uden problem med FileShare.None, selvom det vises/redigeres af Paint.NET. Så ideen vandt ikke.





Har Paint.NET en Remoting-grænseflade, hvor jeg kan forhøre den for hvilke filer den har åbnet? det ville passe til mine formål.

Bedste reference


Desværre er der ingen bedre måde. Applikationer som Microsoft Outlook har det samme problem, når du redigerer vedhæftede filer. Du kan forsøge at gøre en bedste gæt ved at tage en alt-i-oven-tilgang.


For eksempel, når din ansøgning bliver aktiv igen efter shelling ud til Paint.NET (eller hvad redaktør de har tilknyttet) kan du tjekke for at se, om filen er ændret og måske spørge om de er færdige. Hvis processen lukker, kan du bruge det som et ganske sikkert tegn på, at de er færdige og springe over spørgsmålet. Hvis filsystemet watcher registrerer ændringer, kan du køere dem, indtil Paint.NET ikke længere er aktivt osv.


Men mange applikationer vil ikke holde nogen form for lås på en fil, mens du redigerer den. Jeg er temmelig sikker Paint.NET gør det ikke. Applikationer som Office gør, og det er nok årsagen til, at redigering af Word/Excel vedhæftede filer fra Outlook er meget mere pålidelig end almindelige tekstfiler.

Andre referencer 1


Efter at have fiddlet med dette lidt tror jeg, at UI Automation vil tilfredsstille. Ved hjælp af System.Windows.Automation klasserne, der var nye i .NET 3.0, kan jeg spørge om indholdet af andre Windows på maskinen, og jeg kan finde en Windows til et givet proces ID. Så det er et spørgsmål om [6]



  • Find PaintDotNet.exe-processen via en søgning i System.Diagnostics.Process.GetProcesses

  • at få AutomationElement til hovedvinduet i PaintDotNet-appen

  • Kontrollerer egenskaben 'Navn' i vinduet.

  • Når det skifter fra 'myfile.jpg' til noget andet, så ved jeg Paint.NET har
    stoppet med at redigere filen.

  • Hvis jeg får en ElementNotAvailableException, betyder det, at Paint.NET er ophørt.



Jeg har ikke testet det meget, men denne kode ser ud til at virke til mine formål: [7] [8] [9]


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.");
        }
    }
}


Metoden FindChildByProcessId er en forlængelsesmetode fra dette blogindlæg. Det ser ud som dette: [10]


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


Dette virker lidt uortodoks, men det virker bare. Den vanskeligste del er timingen - du skal vente længe nok for at lade appen starte, hvilket kan være 1 sekund eller det kan være 7 sekunder. Prøv derefter at vedhæfte det med UIAutomation klasserne.