In my Windows Phone 7 app, I want ContentPanel's background to change its color within a specified time (3 seconds in this case). Basically I want it to be "flashing".
But the problem is that the changes do not appear while the loop is working, the color changes only once, after the loop is done working. Why?
byte R;
TimeSpan ts = new System.TimeSpan(0, 0, 0, 3);
DateTime dt1 = new DateTime();
DateTime dt2 = new DateTime();
requirement = true;
while (requirement)
{
R = Convert.ToByte(0.5 * 255 * (1 + Math.Sin(DateTime.Now.Millisecond)));
ContentPanel.Background = new SolidColorBrush(Color.FromArgb(255, R, 125, 70));
dt1 = DateTime.Now;
dt2 = DateTime.Now;
dt2.Subtract(dt1);
if (dt2.Subtract(ts).CompareTo(dt1) > 0) requirement = false;
}
Is it even possible?
Looks like your loop is too tight.
Try this instead:
private DispatcherTimer _timer;
private void StartFlash()
{
_timer = new DispatcherTimer();
_timer.Interval = new TimeSpan(0,0,1);
_timer.Tick += (s,e) => ChangeColour;
}
private void StopFlash()
{
_timer = null;
}
private void ChangeColour() {
// Your colour changing logic goes here
ContentPanel.Background = new SolidColorBrush(Color.FromArgb(a,r,g,b));
}
Put that code in a class. Call StartFlash() somewhere. ChangeColour will execute every second.
You are asking for DateTime.Now way too fast so the difference will equate to 0 as DateTime's accuracy does not go as far as nanoseconds (Dates are marked by milliseconds from the unix epoch after all).
You might want to limit the while with more solid logic.
Try using the DispatcherTimer to do in async way.
The UI is not updated during your method execution, moreover if you work in the UI thread.
Related
Hey I have an rather specific issue.
I am building an metronom, and this metronom also shows boxes, which will change their color in the given tact in bpm. the highest possible bpm is 400bpm with 4/4 beats. that means the fastest change of color should happen every: 37,5 ms.
The change of color will last some milliseconds.
Until now i tried to realize that with a timer:
timer = new System.Timers.Timer() { AutoReset = true, SynchronizingObject = null };
private async void timer1_Elapsed(object sender, ElapsedEventArgs e)
{
boxViewLast = (BoxView)beatDisplay.Children[(int)lastI];
boxView = (BoxView)beatDisplay.Children[(int)i];
boxViewLast.Color = boxColor;
boxView.Color = transColor;
await Task.Delay((int)BeatMilliseconds);
boxView.Color = boxColor;
lastI = i;
i++;
if (i >= numOfChildren)
{
i = 0;
}
timer.AutoReset = Tempo == 1 && Play;
}
But in the UI I see a flickering some times if the color is changing fast and sometimes it is not even changing. I guess that resources are getting blocked and so the change can not be fullfilled in the given time. Is there a way to have UI change async and very performant? But I also need a very pricise timer
No reason to await Task.Delay inside the callback. You can use the timer to define the interval between callbacks:
var lastTime = DateTime.Now;
var times = new List<TimeSpan>(1000);
var timer = new System.Timers.Timer() { Enabled = true, Interval = 32, AutoReset = true};
timer.Elapsed += TimerHandler;
Console.WriteLine("Starting timer");
timer.Start();
await Task.Delay(TimeSpan.FromSeconds(3));
timer.Stop();
foreach (var time in times)
{
Console.WriteLine($"{time.TotalMilliseconds}ms passed");
}
void TimerHandler(object? sender, System.Timers.ElapsedEventArgs e)
{
TimeSpan timePassed = e.SignalTime - lastTime;
times.Add(timePassed);
lastTime = DateTime.Now;
}
It's going to be somewhat accurate:
30.5771ms passed
31.0725ms passed
30.8268ms passed
31.0783ms passed
30.5758ms passed
31.4693ms passed
31.0038ms passed
32.1051ms passed
31.0289ms passed
31.1313ms passed
30.9087ms passed
31.0877ms passed
31.9015ms passed
30.7389ms passed
46.8875ms passed
31.4987ms passed
31.7549ms passed
The following dispatcher runs every 1 minute, counting from the time is invoked its Start() method...but what I actually need is that it ticks on every change in the minute component of the system time. Any idea?
This is a windows application (WPF).
DispatcherTimer hourTimer = new DispatcherTimer(DispatcherPriority.Normal)
{
Interval = new TimeSpan(0, 1, 0)
};
hourTimer.Tick += (sender,e) => { renderTime(); };
hourTimer.Start();
You can't get a "metronome quality beat" from any timer that uses a single thread to execute the tick. This is because the thread may be blocked when the tick needs to happen.
The best you can do is calculate the time till the next tick and reset the duration at the start of the tick event.
var now = DateTime.UtcNow;
var nextMinute = now.AddTicks(-(now.Ticks%TimeSpan.TicksPerMinute)).AddMinutes(1);
DispatcherTimer hourTimer = new DispatcherTimer(DispatcherPriority.Normal)
{
Interval = nextMinute - DateTime.UtcNow
};
hourTimer.Tick += (sender, e) =>
{
var correctionNow = DateTime.UtcNow;
var timeCorrection = correctionNow.AddTicks(-(correctionNow.Ticks % TimeSpan.TicksPerMinute)).AddMinutes(1);
hourTimer.Interval = timeCorrection - DateTime.UtcNow;
renderTime();
};
hourTimer.Start();
I'm trying to code a loop to re execute a block of code 3 times. At the moment the code starts and executes once but doesn't repeat as intended with using the for loop.
I've set a break point on the for loop and it only goes through the loop once.
private async void startBtn_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
int i;
int roundMax = 3;
for (i = 1; i <= roundMax; i++)
{
//delay stop watch start to allow time to get ready.
TimeSpan time = TimeSpan.FromSeconds(1);
await System.Threading.Tasks.Task.Delay(time);
//set text box editing to false to prevent illegal input.
wrkTbx.IsEnabled = false;
restTbx.IsEnabled = false;
roundSlider.IsEnabled = false;
roundsTbx.IsEnabled = false;
StopGoCvs.Background = new SolidColorBrush(Colors.Green);
//startSoundElmt.Play();
// set up the timer
myTimer = new DispatcherTimer();
myTimer.Interval = new TimeSpan(0, 0, 0, 0, 1);
myTimer.Tick += myTimer_Tick;
// start both timers
myTimer.Start();
myStopwatch.Start();
}
}
this is a logical issue, and I suspect it exits the for loop at some point, Assumming you're using Visual Studio, I would use Breakpoints at every steps and run the program to see where it fails, you may be missing a return or else somewhere
I want a DispatcherTimer to restart everytime the conditions are not met. Only when the if-condition is met for 5 seconds, the method can continue.
How should I stop the Dispatchertimer? The timeToWait variable is set to 3000, that works as intended.
Below is the code in C#. It is not responding as I want. It only starts, but never stops or restarts. I am making a WPF application.
dispatcherTimerStart = new DispatcherTimer();
if (average >= centerOfPlayingField - marginOfDetection && average <= centerOfPlayingField + marginOfDetection)
{
dispatcherTimerStart.Interval = TimeSpan.FromMilliseconds(timeToWait);
dispatcherTimerStart.Tick += new EventHandler(tick_TimerStart);
startTime = DateTime.Now;
dispatcherTimerStart.Start();
} else
{
dispatcherTimerStart.Stop();
dispatcherTimerStart.Interval = TimeSpan.FromMilliseconds(timeToWait);
}
private void tick_TimerStart(object sender, EventArgs args)
{
DispatcherTimer thisTimer = (DispatcherTimer) sender;
thisTimer.Stop();
}
you need to preserve the dispatcherTimer that enter your if block because in your else block you are stopping the new instance of DispatcherTimer not the one that entered the if block.
take a class level field
DispatcherTimer preservedDispatcherTimer=null;
var dispatcherTimerStart = new DispatcherTimer();
if (average >= centerOfPlayingField - marginOfDetection && average <= centerOfPlayingField + marginOfDetection)
{
**preservedDispatcherTimer = dispatcherTimerStart;**
dispatcherTimerStart.Interval = TimeSpan.FromMilliseconds(timeToWait);
dispatcherTimerStart.Tick += new EventHandler(tick_TimerStart);
startTime = DateTime.Now;
dispatcherTimerStart.Start();
}
//use preservedDispatcherTimer in else
else if(preservedDispatcherTimer!=null)
{
preservedDispatcherTimer.Stop();
preservedDispatcherTimer.Interval = TimeSpan.FromMilliseconds(timeToWait);
}
I want to make an image viewer in C# Visual Studio 2010 which displays images one by one after seconds:
i = 0;
if (image1.Length > 0) //image1 is an array string containing the images directory
{
while (i < image1.Length)
{
pictureBox1.Image = System.Drawing.Image.FromFile(image1[i]);
i++;
System.Threading.Thread.Sleep(2000);
}
When the program starts, it stops and just shows me the first and last image.
Thread.Sleep blocks your UI thread use System.Windows.Forms.Timer instead.
Use a Timer.
First declare your Timer and set it to tick every second, calling TimerEventProcessor when it ticks.
static System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();
myTimer.Tick += new EventHandler(TimerEventProcessor);
myTimer.Interval = 1000;
myTimer.Start();
Your class will need the image1 array and an int variable imageCounter to keep track of the current image accessible to the TimerEventProcessor function.
var image1[] = ...;
var imageCounter = 0;
Then write what you want to happen on each tick
private static void TimerEventProcessor(Object myObject, EventArgs myEventArgs) {
if (image1 == null || imageCounter >= image1.Length)
return;
pictureBox1.Image = Image.FromFile(image1[imageCounter++]);
}
Something like this should work.
Yes, because Thread.Sleep blocks the UI thread during the 2s.
Use a timer instead.
If you want to avoid using Timer and defining an event handler you can do this:
DateTime t = DateTime.Now;
while (i < image1.Length) {
DateTime now = DateTime.Now;
if ((now - t).TotalSeconds >= 2) {
pictureBox1.Image = Image.FromFile(image1[i]);
i++;
t = now;
}
Application.DoEvents();
}