I have this code
Color[] colours = new Color[5]{Color.Red, Color.Blue, Color.Green, Color.Yellow, Color.Black};
public int randGen(int lower, int upper)
{
Random random = new Random();
return random.Next(lower, upper);
}
public PlayGame()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
changeColour();
}
public void changeColour()
{
int milliseconds = randGen(1000, 5000);
int count = 0;
Device.StartTimer(TimeSpan.FromMilliseconds(milliseconds), () =>
{
var layout = new StackLayout { Padding = new Thickness(5, 10) };
var label = new Label { Text = "Time: ", TextColor = Color.Green, FontSize = 25 };
layout.Children.Add(label);
label.Text += milliseconds.ToString();
this.Content = layout;
if (count < 4)
{
BackgroundColor = colours[count];
count++;
milliseconds = randGen(1000, 5000);
return true;
}
else
{
BackgroundColor = Color.Black;
return false;
}
}
);
}
Which has an array of colours. The idea is that every 1-5 seconds (which should be random each time), the background colour should change, and the text should write how long the screen was on for.
Currently, however, the time shown in the text is not reflective of the time each screen shows for, and I have some speculative concern that milliseconds in:
Device.StartTimer(TimeSpan.FromMilliseconds(milliseconds)
doesn't change at all. Any ideas?
this is what I would do - have your timer fire every second (or whatever granularity you need) but only execute your code every X times
using System.Timers;
// these are class variables
Timer timer;
int timecount = 0;
// adjust this dynamically so your code only executes every 1-n seconds
int interval = 1;
// to this wherever you want to start the timer
timer = new Timer();
timer.Elapsed += Timer_Elapsed;
// fire every 1 sec
timer.Interval = 1000;
timer.Start();
// timer event handler
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
timecount++;
if (timecount == interval)
{
timecount = 0;
// do other stuff here
}
}
Related
I have a form that displays queue of messages and number this messages can be changed. Really I want to blink label (queue length) when the number of messages were increased to improve form usability.
Should I implement custom control and use additional thread or timer to change color of label? Has anybody implemented so functionality? What is the best solution (less resources and less performance degradation) to implement so behaviour?
SOLUTION:
Form's component with timer that can restrict number of animations per second and implement fade out effect to external control background color.
The following is blinking using async and await
private async void Blink(){
while (true){
await Task.Delay(500);
label1.BackColor = label1.BackColor == Color.Red ? Color.Green : Color.Red;
}
}
I know this is a really old post, but anyone looking for something a little more versatile than the Boolean solutions posted may get some use out of the following:
using System.Diagnostics;
using System.Threading.Tasks;
private async void SoftBlink(Control ctrl, Color c1, Color c2, short CycleTime_ms, bool BkClr)
{
var sw = new Stopwatch(); sw.Start();
short halfCycle = (short)Math.Round(CycleTime_ms * 0.5);
while (true)
{
await Task.Delay(1);
var n = sw.ElapsedMilliseconds % CycleTime_ms;
var per = (double)Math.Abs(n - halfCycle) / halfCycle;
var red = (short)Math.Round((c2.R - c1.R) * per) + c1.R;
var grn = (short)Math.Round((c2.G - c1.G) * per) + c1.G;
var blw = (short)Math.Round((c2.B - c1.B) * per) + c1.B;
var clr = Color.FromArgb(red, grn, blw);
if (BkClr) ctrl.BackColor = clr; else ctrl.ForeColor = clr;
}
}
Which you can call like such:
SoftBlink(lblWarning, Color.FromArgb(30, 30, 30), Color.Red,2000,false);
SoftBlink(lblSoftBlink, Color.FromArgb(30, 30, 30), Color.Green, 2000,true);
Timer timer = new Timer();
timer.Interval = 500;
timer.Enabled = false;
timer.Start();
if( messagesNum > oldMessagesNum)
timer.Tick += new EventHandler( timer_Tick );
else
timer.Tick -= timer_Tick;
void timer_Tick( object sender, EventArgs e )
{
if(messageLabel.BackColor == Color.Black)
messageLabel.BackColor = Color.Red;
else
messageLabel.BackColor = Color.Black;
}
Here is a pretty simple implementation that would work inside your form. You could also create a custom control with the same code and just throw the Timer.Start() into a method for that control.
Create your own UserControl for this, one that inherits from Label instead of from Control directly. Add a StartBlinking method, in which you start a Timer object whose tick event alters the style of the label (changing the BackgroundColor and ForegroundColor properties each time to create the blink effect).
You could also add a StopBlinking method to turn it off, or you could have your Timer stop itself after 5 seconds, perhaps.
You can create a custom component and events to start blinking --which I think is a good solution. The Blinking you can implement with a timer.
Can you use an animated .gif instead (perhaps as the background of the number)? it would make it look like old school web pages, but it might work.
You can use Timer class here.
Here what I have implemented.
Label color blinking on Button_click Event.
//click event on the button to change the color of the label
public void buttonColor_Click(object sender, EventArgs e)
{
Timer timer = new Timer();
timer.Interval = 500;// Timer with 500 milliseconds
timer.Enabled = false;
timer.Start();
timer.Tick += new EventHandler(timer_Tick);
}
void timer_Tick(object sender, EventArgs e)
{
//label text changes from 'Not Connected' to 'Verifying'
if (labelFirst.BackColor == Color.Red)
{
labelFirst.BackColor = Color.Green;
labelFirst.Text = "Verifying";
}
//label text changes from 'Verifying' to 'Connected'
else if (labelFirst.BackColor == Color.Green)
{
labelFirst.BackColor = Color.Green;
labelFirst.Text = "Connected";
}
//initial Condition (will execute)
else
{
labelFirst.BackColor = Color.Red;
labelFirst.Text = "Not Connected";
}
}
this is how i ended up doing it
public partial class MemberDisplay : Form
{
public string Input;
public int MASS_STOP = 1;
public MemberDisplay(string msg)
{
InitializeComponent();
State_Entry();
Input = msg;
}
public void State_Entry()
{
this.SpecialFocus.Select();
this.lbl_TimerTest.Hide();
}
private async void RunBlinkyTest(string msg)
{
while (msg == "GO" && (MASS_STOP == 0))
{
await Task.Delay(500);
lbl_TimerTest.ForeColor =
lbl_TimerTest.ForeColor == Color.Red ?
Color.Black :
Color.Red;
if (msg == "STOP" && (MASS_STOP == 1)) { return; }
}
}
private void btn_TimeTest_Click(object sender, EventArgs e)
{
if (btn_TimeTest.Text == "GO")
{
this.lbl_TimerTest.Show();
MASS_STOP = 0;
RunBlinkyTest("GO");
btn_TimeTest.Text = "STOP";
return;
}
if (btn_TimeTest.Text == "STOP")
{
MASS_STOP = 1;
RunBlinkyTest("STOP");
this.lbl_TimerTest.ForeColor = Color.Black;
this.lbl_TimerTest.Hide();
btn_TimeTest.Text = "GO";
return;
}
}
}
I am new to C# and Winforms and try to make a moving panel. It should move right until the end of my window and then back left. It should bounce from side to side. But the only thing happened after hours of trying is that it moves left and stops.
Using this form tools:
Timer = tmrMoveBox (interval: 50)
Panel = pnlBox
Label = lblXY (for showing the X and Y coordinates in the form)
Here are my first best try:
private void tmrMoveBox(object sender, EventArgs e)
{
if (pnlBox.Location.X <= 316)
{
for (int i = 0; i <= 316; i++)
{
pnlBox.Location = new Point(
pnlBox.Location.X + 2, pnlBox.Location.Y);
string BoxLocationToString = pnlBox.Location.ToString();
lblXY.Text = BoxLocationToString;
}
}
else if (pnlBox.Location.X >= 0)
{
for (int i = 0; i >= 316; i++)
{
pnlBox.Location = new Point(
pnlBox.Location.X - 2, pnlBox.Location.Y);
string BoxLocationToString = pnlBox.Location.ToString();
lblXY.Text = BoxLocationToString;
}
}
}
And the second best try:
private void tmrMoveBox(object sender, EventArgs e)
{
int runBox = 1;
if(runBox == 1)
{
while (pnlBox.Location.X <= 316)
{
pnlBox.Location = new Point(
pnlBox.Location.X + 2, pnlBox.Location.Y);
string BoxLocationString = pnlBox.Location.ToString();
lblXY.Text = BoxLocationString;
runBox = 0;
}
}
else
{
while(pnlBox.Location.X > 0)
{
pnlBox.Location = new Point(
pnlBox.Location.X - 2, pnlBox.Location.Y);
string BoxLocationString = pnlBox.Location.ToString();
lblXY.Text = BoxLocationString;
runBox = 1;
}
}
}
Tried to use a while loop too but then the panel just disappears.
I'm no expert and just set this moving panel as a goal for myself. Hope anyone can give me a tip.
EDIT:
Form1.Designer.cs
this.timer1.Interval = 50;
this.timer1.Tick += new System.EventHandler(this.tmrMoveBox);
this.timer1.Start();
this.timer1.Step = 2;
Depending on what you're using:
Windows Forms
WPF
Create a Timer and subscribe to the Tick event. Also, you should create new int property Step.
1. Windows Forms:
System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
int Step;
Form1 ()
{
InitializeComponent()
....
t.Interval = 15000; // specify interval time as you want
t.Tick += new EventHandler(timer_Tick);
t.Start();
this.Step = 2;
}
And in ticks event handler put your logic, without while
void timer_Tick(object sender, EventArgs e)
{
if (pnlBox.Location.X >= 316)
{
Step = -2;
}
if (pnlBox.Location.X <= 0)
{
Step = 2;
}
pnlBox.Location = new Point(
pnlBox.Location.X + Step , pnlBox.Location.Y);
string BoxLocationString = pnlBox.Location.ToString();
lblXY.Text = BoxLocationString;
}
So your box will move on one step per one timer tick.
1. WPF:
As System.Windows.Forms.Timer is not available, you may use System.Windows.Threading.DispatcherTimer:
using System.Windows.Threading;
DispatcherTimer t = new DispatcherTimer();
t.Interval = new TimeSpan(0, 0, 15); // hours, minutes, seconds (there are more constructors)
t.Tick += Timer_Tick;
t.Start();
Here is the code I used:
int d= 10;
private void timer1_Tick(object sender, EventArgs e)
{
//Reverse the direction of move after a collision
if(panel1.Left==0 || panel1.Right==this.ClientRectangle.Width)
d = -d;
//Move panel, also prevent it from going beyond the borders event a point.
if(d>0)
panel1.Left = Math.Min(panel1.Left + d, this.ClientRectangle.Width - panel1.Width);
else
panel1.Left = Math.Max(panel1.Left + d, 0);
}
Note:
To check the collision you should check:
Collision with left: panel1.Left==0
Collision with right: panel1.Right==this.ClientRectangle.Width
You should not allow the panel goes beyond the borders even a point, so:
The maximum allowed value for your panel left is this.ClientRectangle.Width - panel1.Width
The minimum allowed value for your panel left is 0
Also It's better to use this.ClientRectangle.Width instead of using hard coded 316.
I'm sending to my method different images and I want insert some effect to this change.
How can I fade in and fade out images?
private void ShowImage(Image image, ImageLayout imageLayout, int numberOfSeconds)
{
try
{
if (this.image_timer != null)
this.KillImageTimer();
this.customer_form.DisplayImage(image, imageLayout);
this.image_timer = new Timer();
this.image_timer.Tick += (object s, EventArgs a) => NextImage();
this.image_timer.Interval = numberOfSeconds* 1000;
this.image_timer.Start();
}
catch
{
//Do nothing
}
public void DisplayImage(Image image, ImageLayout imageLayout)
{
panel1.BackgroundImage = image;
panel1.BackgroundImageLayout = imageLayout;
}
There are no built-in fading transitions in Winforms.
So you will need to write one yourself.
The simplest one I can think of uses a second Panel, that is layered upon the first one and in fact needs to be inside the first Panel or else the transparency effect won't work..
Here is the setup, using two Panels:
public Form1()
{
InitializeComponent();
pan_image.BackgroundImage = someImage;
pan_layer.Parent = pan_image;
pan_layer.BackColor = pan_image.BackColor;
pan_layer.Size = pan_image.Size;
pan_layer.Location = Point.Empty;
}
For the fading animation I use a Timer. This is a quick code example:
Timer timer1 = new Timer();
int counter = 0;
int dir = 1; // direction 1 = fade-in..
int secondsToWait = 5;
int speed1 = 25; // tick speed ms
int speed2 = 4; // alpha (0-255) change speed
void timer1_Tick(object sender, EventArgs e)
{
// we have just waited and now we fade-out:
if (dir == 0)
{
timer1.Stop();
dir = -speed2;
counter = 254;
timer1.Interval = speed2;
timer1.Start();
}
// the next alpha value:
int alpha = Math.Min(Math.Max(0, counter+= dir), 255);
button1.Text = dir > 0 ? "Fade In" : "Fade Out";
// fully faded-in: set up the long wait:
if (counter >= 255)
{
timer1.Stop();
button1.Text = "Wait";
timer1.Interval = secondsToWait * 1000;
dir = 0;
timer1.Start();
}
// fully faded-out: try to load a new image and set direction to fade-in or stop
else if (counter <= 0)
{
if ( !changeImage() )
{
timer1.Stop();
button1.Text = "Done";
}
dir = speed2;
}
// create the new, semi-transparent color:
Color col = Color.FromArgb(255 - alpha, pan_image.BackColor);
// display the layer:
pan_layer.BackColor = col;
pan_layer.Refresh();
}
I start it in a Button, on which I also show the current state:
private void button1_Click(object sender, EventArgs e)
{
dir = speed2;
timer1.Tick += timer1_Tick;
timer1.Interval = speed1;
timer1.Start();
}
As you can see I use two speeds you can set: One to control the speed of the Timer and one to control the steps by which the transparency changes on each Tick.
The effect is created by simply changing the Color from the BackgroundColor of the image Panel to fully transparent and back, waiting in between for a specified number of seconds.
And the end of the effect I call a function changeImage() to change the images. If this function returns false the Timer is stopped for good..
I'm pretty sure this could be written in a cleaner and more elegant way, but as it is it seems to work..
Update
for flicker-free display use a double-buffered control, like this Panel subclass:
class DrawPanel : Panel
{
public DrawPanel() { DoubleBuffered = true; }
}
Here is a sample implementation for changeImage:
bool changeImage()
{
if (pan_image.BackgroundImage != null)
{
var img = pan_image.BackgroundImage;
pan_image.BackgroundImage = null;
img.Dispose();
}
pan_image.BackgroundImage = Image.FromFile(imageFiles[index++]);
return index < imageFiles.Count;
}
It assumes two class level variables: a List<string> imageFiles filled with file names of images for a slide-show and an int index = 0.
I'm very new to WP8 dev and c#. I'm trying to make a loop that counts up by n on an interval. I want to press a button to increment n.
Here is my code right now:
namespace Petsounds {
public partial class MainPage : PhoneApplicationPage {
float clicks = 0;
float clickers = 0;
float clickerBuyers = 0;
float clickerCost = 5;
float clickerBuyerCost = 500;
long savedTime = DateTime.Now.Ticks / TimeSpan.TicksPerSecond;
bool buyClickerButtonFlag = false;
bool clickButtonFlag = false;
// Constructor
public MainPage() {
InitializeComponent();
//
DispatcherTimer t = new DispatcherTimer();
t.Interval = TimeSpan.FromMilliseconds(10);
t.Tick += (s, e) => startLoop();
t.Start();
}
private void clickButtonOnClick(object sender, RoutedEventArgs e) {
clickButtonFlag = true;
System.Diagnostics.Debug.WriteLine("clicked!" + clicks);
}
private void buyClickerButtonOnClick(object sender, RoutedEventArgs e) {
buyClickerButtonFlag = true;
}
private void startLoop() {
if (true) {
long nowTime = savedTime;
long timePassed = nowTime - savedTime;
//user input
if (clickButtonFlag) {
clickButtonFlag = false;
clicks++;
System.Diagnostics.Debug.WriteLine("clicked!" + clicks);
}
if (buyClickerButtonFlag) {
buyClickerButtonFlag = false;
if (clicks > clickerCost) {
clickers++;
clicks -= clickerCost;
clickerCost *= 1.6F;
}
System.Diagnostics.Debug.WriteLine("clicker bought!" + clickers);
}
//update vars
if (timePassed > TimeSpan.TicksPerSecond) {
savedTime = nowTime;
nowTime = DateTime.Now.Ticks / TimeSpan.TicksPerSecond;
clicks += clickers;
}
//update display
clickCount.Text = clicks.ToString();
buyClickerButtonCost.Text = "Cossst " + clickerCost.ToString();
}
}
}
}
My button's are inconsistent, and if I remove the thread, the buttons are responsive (but of course the counter doesn't work.)
EDIT:
I've changed
DispatcherTimer t = new DispatcherTimer();
t.Interval = TimeSpan.FromMilliseconds(10);
t.Tick += (s, e) => startLoop();
t.Start();
to
Timer myTimer = new Timer(startLoop);
myTimer.Change(1000, 10);
And now get an error:
A first chance exception of type 'System.UnauthorizedAccessException' occurred in System.Windows.ni.dll
on line
clickCount.Text = clicks.ToString();
First of all... you will quickly find that 10ms is not really 10ms... It might not even be that close... If you did 1000ms... that would be expected to be more accurate.
Also, a DispatcherTimer is going to queue up a function call to the GUI thread each interval... which means you are flooding the GUI thread with startLoop() calls. This doesn't give the thread much time to update anything else... like your buttons.
There is a different approach you might want to consider.
If your task is to increment a numeric value when a user touches a button (and have the numbers increase at a steady pace) consider using the RepeatButton.
RepeatButton: Represents a control that raises its Click event repeatedly from the time it is pressed until it is released.
XAML
<!--
Delay: The time, in milliseconds, the RepeatButton waits
when it is pressed before it starts repeating the click action.
Interval: The time, in milliseconds, between repetitions
of the click action, as soon as repeating starts.
-->
<RepeatButton Content='Buy'
Interval='50' Delay='100'
Click='RepeatButton_Click' />
Code
private float buyCounter = 0;
private void RepeatButton_Click(object sender, RoutedEventArgs e) {
buyCounter += 1;
buyClickerButtonCost.Text = buyCounter.ToString();
}
It's like #Andrew said - DispatcherTimer works on UI thread and with so small intervall you are blocking it.
If you want such a small interval you can use Timer on different Thread:
public MainPage()
{
InitializeComponent();
System.Threading.Timer myTimer = new Timer(MyTimerCallback);
myTimer.Change(1000, 10);
}
private static int value = 0;
private static void MyTimerCallback(object state)
{
value++;
}
But you must remember that you use it on different Thread - this Timer has no access to your UI elements (buttons and so on).
EDIT
You convinced me to check it:
static float clicks = 0;
static float clickers = 0;
static float clickerCost = 5;
static long savedTime = DateTime.Now.Ticks / TimeSpan.TicksPerSecond;
static bool buyClickerButtonFlag = false;
static bool clickButtonFlag = false;
public MainPage()
{
InitializeComponent();
first.Click += ShowCounter;
DispatcherTimer t = new DispatcherTimer();
t.Interval = TimeSpan.FromSeconds(5);
t.Tick += ShowCounter;
t.Start();
System.Threading.Timer myTimer = new Timer(MyTimerCallback);
myTimer.Change(10, 10);
}
private void ShowCounter(object sender, EventArgs e)
{
textBlck.Text = clicks.ToString();
}
private static void MyTimerCallback(object state)
{
clicks++; // added to check running
if (true)
{
long nowTime = savedTime;
long timePassed = nowTime - savedTime;
//user input
if (clickButtonFlag)
{
clickButtonFlag = false;
clicks++;
System.Diagnostics.Debug.WriteLine("clicked!" + clicks);
}
if (buyClickerButtonFlag)
{
buyClickerButtonFlag = false;
if (clicks > clickerCost)
{
clickers++;
clicks -= clickerCost;
clickerCost *= 1.6F;
}
System.Diagnostics.Debug.WriteLine("clicker bought!" + clickers);
}
//update vars
if (timePassed > TimeSpan.TicksPerSecond)
{
savedTime = nowTime;
nowTime = DateTime.Now.Ticks / TimeSpan.TicksPerSecond;
clicks += clickers;
}
}
}
I tested it on the device and buttons works.
On the other hand - what's the point of putting a method that waits for a flag buton click, when you can put the job easily to button click event. Let it happen when user clicked button - don't check buton state all the time.
I have a circular gauge(progress bar) with a polygon needle that when i select a number in a list box the needle goes up to that degree to resemble a speed in a car(works just fine)
What i want to do is automatically run through the indexes of the list items(0,1,2,3,....60) so the needle slowly rises till it gets to say 60 speed. Then, hold that for as long as i want so i can move a tack needle and run an odometer accordingly. i have tried to use a timer in a MVC class and use a stop watch. I can select the index 0 -6 but it will only just jump to the last one. I am trying to simulate a car dashboard the best i can...What are your thought?
public partial class MainWindow : Window
{
//DispatcherTimer timer;
List<Double> _items = new List<Double>();
DispatcherTimer timer;
public MainWindow()
{
this.InitializeComponent();
listBox1.ItemsSource = new List<double>() { 0,1,2,3,4,5,10,11,12,13,14, 15, 20, 25, 30, 35, 40 };
checkBox1.IsChecked = true;
park.Foreground = Brushes.Red;
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(2500);
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
int second = DateTime.Now.Second;
firstDigitsec = second / 10;
int secondDigitsec = second % 10;
checkBox1.IsChecked = false;
first.Foreground = Brushes.Green;
park.Foreground = Brushes.White;
checkBox2.IsChecked = true;
Stopwatch stopwatch = Stopwatch.StartNew();
listBox1.SelectedIndex = 0;
listBox1.SelectedIndex = 1;
listBox1.SelectedIndex = 2;
listBox1.SelectedIndex = 3;
}
private int _stopw;
public int sw
{
get { return _stopw; }
set
{
_stopw = value;
OnPropertyChanged("");
}
}
private int _firstDigitsec;
public int firstDigitsec
{
get { return _firstDigitsec; }
set
{
_firstDigitsec = value;
OnPropertyChanged("");
/*
if (firstDigitsec < 1)
{
listBox1.SelectedIndex = 0;
}
if (firstDigitsec < 2)
{
*/
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
Since you are using WPF this sounds like an excellent candidate for Animation
Use a Binding to bind your Gauge's Progress property to the Progress property in your viewmodel and apply a DoubleAnimation to animate the Progress property from the previous value to the new value