Frage

Ich bin versucht, den Wiederaufbau einer alten Metronom-Anwendung, die ursprünglich geschrieben wurde, unter Verwendung von MFC in C++ geschrieben werden .NET mit C#.Eine der Fragen, die ich in immer den timer auf "tick" genau genug.

Zum Beispiel, angenommen eine einfache BPM (beats per minute) 120, die timer tick alle 5 Sekunden (oder 500 Millisekunden).Mit diesem als Grundlage für die Zecken, aber nicht ganz genau wie .NET nur garantiert, dass Sie Ihre timer, wird nicht markieren, bevor Sie die verstrichene Zeit vergangen.

Derzeit, dies zu umgehen, für die gleichen 120 BPM oben verwendete Beispiel, ich bin Einstellung, die Zecken so etwas wie 100 Millisekunden, und die spielen nur den Klick-sound auf jedem 5. timer-tick.Dies verbessert die Genauigkeit noch ein wenig, aber wenn fühlt sich ein bisschen wie ein hack.

Also, was ist der beste Weg, um genaue Zecken?Ich weiß, es gibt mehrere Timer zur Verfügung als bei windows forms-timer, die ist leicht verfügbar in Visual Studio, aber ich bin nicht wirklich vertraut mit Ihnen.

War es hilfreich?

Lösung

Es gibt drei timer-Klassen genannt 'Timer' in .NET.Es klingt wie Sie mithilfe von Windows Forms, aber eigentlich finden Sie möglicherweise das System.Threading.Timer-Klasse mehr sinnvoll - aber vorsichtig sein, denn es ruft zurück auf eine pool-thread, so dass Sie kann nicht direkt interagieren mit Ihre form von Rückruf.

Ein anderer Ansatz könnte sein, zu p/invoke Win32 multimedia-Timer - timeGetTime, timeSetPeriod, etc.

Eine schnelle google-fand diese, die nützlich sein könnten http://www.codeproject.com/KB/miscctrl/lescsmultimediatimer.aspx

'Multimedia' (timer) ist das buzz-word zu suchen in diesem Kontext.

Andere Tipps

Was ist die C++ - Anwendung verwenden?Sie können verwenden Sie immer das gleiche oder wickeln Sie den timer-code von C++ in C++/CLI-Klasse.

Ich habe dieses problem bei der Entwicklung einer aktuellen Daten-logging-Projekt.Das problem mit der .NET Timer ( windows.forms, system.threading und system.timer ) ist, dass Sie nur genau auf rund 10 milli-Sekunden, das ist aufgrund der event-Planung integriert .Ich NET glauben.( Ich Rede .NET 2 hier ).Das war nicht akzeptabel für mich und so hatte ich die Verwendung der multimedia-timer ( Sie müssen zum importieren der dll ).Außerdem habe ich eine wrapper-Klasse für alle Timer und so können Sie zwischen Ihnen wechseln, wenn notwendig, mit minimalen code-änderungen.Check out my blog-Beitrag hier:http://www.indigo79.net/archives/27

Eine andere Möglichkeit ist, dass es ist ein Fehler in WPF-Implementierung von DispatcherTimer (es gibt eine Diskrepanz zwischen Millisekunden und ticks verursacht potenziellen Ungenauigkeit abhängig von dem genauen Prozess der Ausführung Zeit) , wie gezeigt, unten:

http://referencesource.microsoft.com/#WindowsBase/Base/System/Windows/Threading/DispatcherTimer.cs,143

class DispatcherTimer
{
    public TimeSpan Interval
    {
        set
        {
            ...
            _interval = value;
            // Notice below bug: ticks1 + milliseconds [Bug1]
            _dueTimeInTicks = Environment.TickCount + (int)_interval.TotalMilliseconds;
        }
    }
}

http://referencesource.microsoft.com/#WindowsBase/Base/System/Windows/Threading/Dispatcher.cs

class Dispatcher
{
    private object UpdateWin32TimerFromDispatcherThread(object unused)
    {
        ...
        _dueTimeInTicks = timer._dueTimeInTicks;
        SetWin32Timer(_dueTimeInTicks);
    }

    private void SetWin32Timer(int dueTimeInTicks)
    {
        ...
        // Notice below bug: (ticks1 + milliseconds) - ticks2  [Bug2 - almost cancels Bug1, delta is mostly milliseconds not ticks]
        int delta = dueTimeInTicks - Environment.TickCount; 
        SafeNativeMethods.SetTimer( 
            new HandleRef(this, _window.Value.Handle),
            TIMERID_TIMERS,
            delta); // <-- [Bug3 - if delta is ticks, it should be divided by TimeSpan.TicksPerMillisecond = 10000]
    }
}

http://referencesource.microsoft.com/#WindowsBase/Shared/MS/Win32/SafeNativeMethodsCLR.cs,505

class SafeNativeMethodsPrivate
{
    ...
    [DllImport(ExternDll.User32, SetLastError = true, ExactSpelling=true, CharSet=System.Runtime.InteropServices.CharSet.Auto)]
    public static extern IntPtr SetTimer(HandleRef hWnd, int nIDEvent, int uElapse, NativeMethods.TimerProc lpTimerFunc);
}

http://msdn.microsoft.com/en-us/library/windows/desktop/ms644906%28v=vs.85%29.aspx

uElapse [in]
Type: UINT
The time-out value, in milliseconds. // <-- milliseconds were needed eventually

Timer-Klassen starten können seltsam verhält, wenn der timer 'aktivieren Sie" Ereignis-code wird nicht ausgeführt, wenn die nächste 'tick' Auftritt.Ein Weg, um dies zu bekämpfen ist, deaktivieren Sie den timer zu Beginn des tick-Ereignis, dann wieder aktivieren am Ende.

Jedoch, dieser Ansatz ist nicht geeignet, in Fällen, in denen der Zeitpunkt der Ausführung des "tick" - code ist nicht akzeptabel, Fehler im timing der Zecke, da der timer wird deaktiviert (nicht zählen), während dieser Zeit.

Wenn das deaktivieren der timer ist eine option, dann kann man auch den gleichen Effekt erzielen, indem Sie die Erstellung einer separaten thread ausführt, Schlafmöglichkeiten für x Millisekunden führt, schläft usw...

System.Windows.Forms.Timer beschränkt sich auf eine Genauigkeit von 55 Millisekunden...

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top