홀로그램맨
8월 26, 2022, 2:08오전
1
안녕하세요 연속으로 질문을 올리게 되었네요 미리 감사드립니다
문제로 넘어가서 wpf로 시간을 출력하는 프로그램을 만들었는데 꽤 자주 시간이 멈추는 모습을 보입니다
혹시 타이머가 멈추는 건가 싶어서 시간이 갱신 될 때마다 list에 넣고 문제 발생 시 중단해서 확인해보면 시간은 제대로 추가가 되어있는데요
주기가 100ms인데 이 정도면 너무 자주 갱신해서 성능에 영향을 주는 정도는 아닐 것 같은데 어떻게 접근하면 될까요
System.Threading.Timer를 만들고 100ms마다 DateTime.Now로 시간을 대입하는 간단한 프로그램입니다
public abstract class ViewModelBase : ObservableObject
{
...
}
public class MainViewModel : ViewModelBase
{
private DateTime _CurrentTime;
public DateTime CurrentTime
{
get => _CurrentTime;
set
{
SetProperty(ref _CurrentTime, value);
}
}
public MainViewModel()
{
List<DateTime> date = new List<DateTime>();
_uiTimer = new Timer(new TimerCallback((s) =>
{
date.Add(DateTime.Now);
if (date.Count > 100)
date.Clear();
CurrentTime = DateTime.Now;
}),
null, TimeSpan.Zero, TimeSpan.FromMilliseconds(100));
}
...
// *.xaml
<Label Content="{Binding CurrentTime}" ContentStringFormat="yyyy-MM-dd hh:mm:ss.fff"/>
1개의 좋아요
nyjin
8월 26, 2022, 2:30오전
2
올려주신 예제대로 테스트를 해 봤을때 별다른 문제는 없었는데요.
차이점이 있다면 별도의 Task
로 PeriodicTimer
타이머를 사용하였습니다.
테스트 했던 코드 공유 드릴게요.
public class MainViewModel : ObservableObject, IDisposable
{
private DateTime _currentTime;
private PeriodicTimer _timer;
private Task _timerTask;
/// <inheritdoc />
public MainViewModel()
{
StartTimer();
}
public DateTime CurrentTime { get => _currentTime; set => SetProperty(ref _currentTime, value); }
/// <inheritdoc />
public void Dispose()
{
_timer.Dispose();
_timerTask.Dispose();
}
/// <summary>
/// 타이머
/// </summary>
private void StartTimer()
{
_timer = new PeriodicTimer(TimeSpan.FromMilliseconds(100));
_timerTask = Task.Run(async () =>
{
while (await _timer.WaitForNextTickAsync().ConfigureAwait(false))
{
CurrentTime = DateTime.Now;
}
});
}
}
<Label Content="{Binding CurrentTime}" ContentStringFormat="yyyy-MM-dd hh:mm:ss.fff" />
3개의 좋아요
홀로그램맨
8월 26, 2022, 3:53오전
3
.net 4.8이라 해당 타이머는 쓸 수가 없네요 ㅠ
답변 감사합니다
1개의 좋아요
nyjin
8월 26, 2022, 4:04오전
4
올려주신 코드 그대로 테스트를 해 보니 중간에 한번씩 짧은 시간 멈추는 모습을 보였는데요.
아마도 Clear 함수 때문 인것으로 보입니다.
만약에 의도하신 Clear 함수가 100개를 유지하기 위함이라면 자료구조를 LinkedList로 바꾸고 100개가 넘을 때 마지막 원소만 삭제하는 방식으로 구성하시면 어떨까 싶네요.
/// <summary>
/// 타이머
/// </summary>
private void StartTimer()
{
LinkedList<DateTime> date = new LinkedList<DateTime>();
_timer = new Timer(new TimerCallback((s) =>
{
date.AddFirst(DateTime.Now);
if (date.Count > 100)
{
date.RemoveLast();
}
CurrentTime = DateTime.Now;
}),
null, TimeSpan.Zero, TimeSpan.FromMilliseconds(100));
}
2개의 좋아요
홀로그램맨
8월 26, 2022, 4:11오전
5
그건 테스트를 위해서 추가한건데 없애도 동일 증상이 발생합니다
다만 특이사항이 있는데 창에 뭔가 액션을 취하면 시간이 다시 흐르네요
예를들어 버튼을 하나 추가하고 시간이 멈췄을 때 버튼에 마우스를 올리면 시간이 흐르고
창을 잡고 조금씩 움직이면 멈추는 현상이 발생 안 합니다
1개의 좋아요
홀로그램맨
8월 26, 2022, 6:29오전
6
ui thread 우선순위 등 관련 있던 것으로
dispatcher timer 를 사용하고 priority를 send, databind등 우선순위 높은 것으로 설정하니 멈춤 없이 동작합니다
단 각 옵션 별 영향이 어떤지는 더 알아봐야할 것 같네요
3개의 좋아요
제가 오래전에 WPF를 만져서 기억이 가물가물한데…
Winform에서 (object).Invoke 하듯이, WPF에서도 Dispatcher.Invoke를 써야했던 기억이 있습니다.
Timer 이벤트 안에서 그냥 ui 변경과 관련된 무언가를 시도하면 Cross-thread 오류가 날겁니다.
(ObservableObject 상속받았고, Label 바인딩을 하고 있기 때문에 아마 맞을듯…)
물론 그럴 때는 예외도 잘 발생되지 않아서 찾기가 힘들죠…
1개의 좋아요
Ctrl + F5 나 바이너리로 실행해보셨나요?
VS 디버그가 아닌 바이너리 실행에서는 전혀 문제가 없네요.
아마도 디버거 개입으로 인해 느려지는 현상이 있는 거 같슴다.
재밌는 건 100ms 보다 작은 값으로 디버그를 돌리면 오히려 덜 멈춘다는 거…=ㅅ=;;;
3개의 좋아요
홀로그램맨
8월 26, 2022, 9:35오전
10
확실히 디버그 없이 실행해보니까 괜찮네요
그나저나 MVVM의 시작을 올려주신 글을 보고 했는데 여기서 뵈니까 신기하네요
코끼리가 눈에 익더라구요 ㅎㅎ
도움이 많이 되어 감사드립니다
2개의 좋아요