これは仕事で私を助けるために書いた最初の適切なC#アプリケーションです(私はスクリプトとコードに関心のあるMSPのヘルプデスクにいます)私はUWPを使ってかなりの労力をかけずに見えるようにしています。時間トラッキングソフトウェアは、ASP.Netで書かれたWebサービスなので、一般的にタイマーは内蔵されていますが、ブラウザのリフレッシュに耐えることはできませんので、チケットに必要なフォーマットに自分自身を書きました。DateTime.Nowベースのタイマーが複数のインスタンスで正確にトラッキングされていない
他のスタックの質問からいくつかのコードを取りました。私の父親(多国籍企業のC#フレームワーク開発者)は、ストップウォッチを使用していないようにタイマーコードの一部を書き直しました。彼は現時点でこの問題を解決することはできません。私は今、どのように動作しているのか理解しています。問題をデバッグする方法ではありません。
複数のタイマーが同時に実行され、新しいタイマーを作成すると他のタイマーはすべて自動的に一時停止されます。 2つの時刻形式(分と小数の時間)を処理するので、コードに表示されているいくつかのプロパティについて説明します。
私の問題は、新しいタイマーを追加すると、他のタイマーがすべて一時停止しますが、以前のタイマー(直前のチケットに戻る)でstartを押すと、新しいタイマーの長さ約10%の差で走っています(走っている時間は正確には決してありません)。
これはノートと現在の時刻(清楚ためのビットを片付け)を追跡するクラスです:
public sealed class JobTimer:INotifyPropertyChanged
{
private DateTime _created; // When the timer was created
private DateTime _started; // When it was most recently started
private TimeSpan _offset; // The saved value to offset the currently running timer
Timer _swTimer; // The actual tick that updates the screen
public JobTimer() : this(TimeSpan.Zero)
{ }
public JobTimer(TimeSpan offset)
{
_offset = offset;
_created = DateTime.Now;
IsNotLocked = true;
}
// Time in seconds
public string TimeMin => string.Format("{0:00}:{1:00}:{2:00}", ElapsedTime.Hours, ElapsedTime.Minutes, ElapsedTime.Seconds);
// Time in decimal hours
public string TimeDec => string.Format("{0}", 0.1 * Math.Ceiling(10 * ElapsedTime.TotalHours));
public DateTime Created => _created;
public TimeSpan ElapsedTime => GetElapsed();
public void Start()
{
_started = DateTime.Now;
_swTimer = new Timer(TimerChanged, null, 0, 1000);
NotifyPropertyChanged("IsRunning");
}
public void Stop()
{
if (_swTimer != null)
{
_swTimer.Dispose();
_swTimer = null;
}
_offset = _offset.Add(DateTime.Now.Subtract(_started));
NotifyPropertyChanged("IsRunning");
}
private TimeSpan GetElapsed()
{
// This was made as part of my own debugging, the ElaspsedTime property used to just be the if return
if (IsRunning)
{
return _offset.Add(DateTime.Now.Subtract(_started));
}
else
{
return _offset;
}
}
// Updates the UI
private void TimerChanged(object state)
{
NotifyPropertyChanged("TimeDec");
NotifyPropertyChanged("TimeMin");
}
public bool IsRunning
{
get { return _swTimer != null; }
}
public void ToggleRunning()
{
if (IsRunning)
{
Stop();
}
else
{
Start();
}
}
}
これはViewModelにに行く:
public class JobListViewModel
{
private readonly ObservableCollection<JobTimer> _list = new ObservableCollection<JobTimer>();
public ObservableCollection<JobTimer> JobTimers => _list;
public JobListViewModel()
{
AddTimer();
}
public void AddTimer()
{
JobTimer t = new JobTimer();
JobTimers.Add(t);
t.Start();
}
public void PauseAll()
{
foreach(JobTimer timer in JobTimers)
{
timer.Stop();
}
}
// Other functions unrelated
}
そして、これは、UIのボタンですそれは新しいタイマー
private void AddTimer_Click(object sender, RoutedEventArgs e)
{
// Create JobTimer
ViewModel.PauseAll();
ViewModel.AddTimer();
// Scroll to newly created timer
JobTimer lastTimer = ViewModel.JobTimers.Last();
viewTimers.UpdateLayout();
viewTimers.ScrollIntoView(lastTimer);
}
を追加]をクリックし、私はそれがポストにダンプするコードの多くのですが、私はcを実現問題が発生している場所を特定できません。 AddTimerボタンを押すと、既存のタイマーが実行されているかどうかにかかわらず、何かがオフセットを変更することがわかりましたが、変更するものを見つけることができません。
確実に問題を再現し、バグが何であるかを確かに言うことができないことがあります。しかし、なぜ、ストップウォッチなしでこれを実装するのが最初の目標でしたか?タイマーの開始と停止を期待しているなら、それを実装するのが最も簡単で信頼性の高い方法だと思います。タイマーが一時停止された合計時間を追跡し、ネット時間からそれを減算しようとしているようです。開始/一時停止/停止機能が組み込まれている完全に使用可能なクラスがある場合、そのポイントは何ですか? –
ローカルで実行する場合は、コードを圧縮することができます。私はUIで毎回再現することができますが、私はどこにブレークポイントを置くべきかわかりません。 'Stopwatch'から離れる理由は、正確にmsである必要はなく、ファイルに保存してからロードする必要があるからです(したがって' _offset'プロパティ)。 'DateTime.Now'を使用して起動し、別の' Now'を取得して開始時刻を引いたものは、停止時間の合計ではなく、実行時間の合計です。また、 'TimeSpan'をテキストとして保存し、後でStopwatchのラッパーを記述せずに再度読み込むこともできます。 – LastElf
また私のお父さんは、最初にこれを行ったときに、あなたがプログラムで持つことができるストップウォッチの数に制限があり、最近のバージョンで変更されていると思われますが、タイマーと同じ方法で処理することはできません。実用的な違いは、パフォーマンスメトリックを取得しようとすると、DateTimeのパフォーマンスが重くなくても正確ではないことです。 – LastElf