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
Related
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
}
}
This question already has answers here:
Error: Must create DependencySource on same Thread as the DependencyObject even by using Dispatcher
(2 answers)
Closed 3 years ago.
I am using a label on multiple forms which display the weather data which is called from a WCF service. I wish to have this update every minute to display the updated weather data without interfering with user interaction.
I get the following error:
"Must create DependencySource on same Thread as the DependencyObject. "
I have a View Model for getting the weather data asynchronously which inherits from ViewModelBase to handle property changed events. The properties from the ViewModel are bound to the label
ViewModel for weather
public class WeatherDataVM : ViewModelBase
{
private string _windString;
private SolidColorBrush _windState;
private DispatcherTimer _timer;
public WeatherDataVM()
{
_timer = new DispatcherTimer(DispatcherPriority.Render);
_timer.Interval = TimeSpan.FromSeconds(10);
_timer.Tick += async (sender, args) => {await Task.Run(() => GetWindAsync()); };
//_timer.Tick += _timer_Tick;
_timer.Start();
GetWind();
}
private void GetWind()
{
var weatherFromService = Services.Instance.EmptyStackService.GetWeather();
var windSpeed = Convert.ToDouble(weatherFromService.Windspeed);
var maxGust = Convert.ToDouble(weatherFromService.Max_Gust_In_Last_Min);
var windSpeedMPH = Math.Round(windSpeed * 1.15078, 1);
var maxGustMPH = Math.Round(maxGust * 1.15078, 1);
var windString = $"W/S: {windSpeedMPH}({maxGustMPH})";
var windState = new Color();
if (windSpeed >= 40)
windState = Color.FromRgb(255, 64, 64);
else if (windSpeed >= 24)
windState = Color.FromRgb(255, 212, 128);
else
windState = Color.FromRgb(0, 255, 0);
_windState = new SolidColorBrush(windState);
_windString = windString;
}
private async Task GetWindAsync()
{
var weatherFromService = Services.Instance.EmptyStackService.GetWeather();
var windSpeed = Convert.ToDouble(weatherFromService.Windspeed);
var maxGust = Convert.ToDouble(weatherFromService.Max_Gust_In_Last_Min);
var windSpeedMPH = Math.Round(windSpeed * 1.15078, 1);
var maxGustMPH = Math.Round(maxGust * 1.15078, 1);
var windString = $"W/S: {windSpeedMPH}({maxGustMPH})";
var windState = new Color();
if (windSpeed >= 40)
windState = Color.FromRgb(255, 64, 64);
else if (windSpeed >= 24)
windState = Color.FromRgb(255, 212, 128);
else
windState = Color.FromRgb(0, 255, 0);
WindState = new SolidColorBrush(windState);
WindString = windString;
}
public string WindString
{
get { return _windString; }
set
{
if (_windString == value)
return;
_windString = value;
OnPropertyChanged("WindString");
}
}
public SolidColorBrush WindState
{
get { return _windState; }
set
{
if (_windState == value)
return;
_windState = value;
OnPropertyChanged("WindState");
}
}
}
ViewModelBase
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Xaml on view for label
<Label x:Name="lblWeather" Content="{Binding WindString}" Foreground="black" Background="{Binding WindState}" Style="{DynamicResource SmallLabel}" />
code behind view in constructor
lblWeather.DataContext = new WeatherDataVM();
the weather label should change each time the timer ticks. Instead it throws an error.
You can create a brush on a background thread if you freeze it:
var brush = new SolidColorBrush(windState);
brush.Freeze();
WindState = brush;
But it doesn't make much sense to use a DispatcherTimer if you just call Task.Run in the Tick event handler.
Provided that your event handler only creates brushes and don't manipulate any UI elements directly (it certainly shouldn't since it's implemented in a view model), you could use a System.Timer.Timer. Its Elapsed event is queued for execution on a thread pool thread where you can query the service without blocking the UI.
I had successfully implemented a databind before but now it has stop working... After putting in some breakpoints I have noticed that the PropertyChange event remains null. I looked up several "solutions" involving using DataContext (not sure where to put it) but still didnt work...
Thanks for any help!
It works for the first initial bind but after it does not wok (when the property changes)
My Code:
My Binding:
//databinding
Binding(newProjectile.CurrentVelocity, lbl_angleoftraveloutput, "AngleOfTravel");
private void Binding(velocity Object, Label Output, string Field)
{
Binding newBinding = new Binding();
newBinding.Source = Object;
newBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
newBinding.Path = new PropertyPath(Field);
newBinding.Mode = BindingMode.TwoWay;
Output.SetBinding(Label.ContentProperty, newBinding);
}
My Object (Part of it):
public class velocity : INotifyPropertyChanged, ICloneable
{
public double AngleOfTravel
{
get { return _AngleOfTravel; }
set
{
_AngleOfTravel = value;
OnPropertyChanged("AngleOfTravel");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string PropertyName)
{
PropertyChangedEventHandler Handler = PropertyChanged;
if (Handler != null)
{
Handler(this, new PropertyChangedEventArgs(PropertyName));
}
}
}
I have analyzed your code. In the button click event - LoadStaticsAndStart you have a statement newParticle.CurrentVelocity = newParticle.InitialVelocity; whic his causing the issue. newParticle.CurrentVelocity is bound to the UI Labels so it will have INotifyPropertyChanged Implementation. But newParticle.InitialVelocity is not bound with UI so it will not have INotifyPropertyChanged so I have commented the line and the UI update for you output labels are working now. Replace the function with the below function.
private void LoadStaticsAndStart(object sender, RoutedEventArgs e)
{
GraphCanvas.Visibility = Visibility.Visible;
DrawAxis();
List<velocity> velocityList = new List<velocity>();
double[,] DisplacementArray = new double[59, 1];
btn_Calculate.Click += OnLoaded;
particle newParticle;
velocity InitialVelocity = new velocity();
ObjectsAndDataStuctures.Environment newEnvironment;
if (FormatCheck(txtb_AngleOLaunch) == false || FormatCheck(txtbox_InitialVelocity) == false || FormatCheck(txtbox_TimeOfFlight) == false)
{
MessageBox.Show(" Input is not valid");
}
else
{
newEnvironment = new ObjectsAndDataStuctures.Environment();
newEnvironment.gravity = -9.8; // gravity remove when needed or changed
InitialVelocity.Magnitude = Convert.ToDouble(txtbox_InitialVelocity.Text); // collecting variables.
InitialVelocity.AngleOfTravel = Convert.ToDouble(txtb_AngleOLaunch.Text); // collecting variables.
newParticle = new particle(InitialVelocity, Convert.ToDouble(txtbox_TimeOfFlight.Text));
stk_pnl_inputvar.Visibility = Visibility.Collapsed;
CreateLabels(newParticle);
newParticle.CalculateHComponent();
newParticle.CalculateVComponent();
MPP(newParticle, newEnvironment);
OnLoaded(this, e);
if (Convert.ToDouble(txtbox_TimeOfFlight.Text) > 60)
{
TimeConstant = Convert.ToDouble(txtbox_TimeOfFlight.Text) / 60;
}
else
{
TimeConstant = 1;
}
double HVelTemp = newParticle.InitialVelocity.HorizontalVelocity * PixelPerMeter;
double VVelTemp = newParticle.InitialVelocity.VerticalVelocity * PixelPerMeter * -1;
Velocity = new Vector(HVelTemp, VVelTemp); // y direction is downwards
acceleration = new Vector(0, -1 * newEnvironment.gravity * PixelPerMeter); // y direction is downwards
aTimer = new System.Windows.Threading.DispatcherTimer();
aTimer.Interval = new TimeSpan(0, 0, 0, 0, 200);
//newParticle.CurrentVelocity = newParticle.InitialVelocity;
//this.DataContext = this;
TimerEvent = (s, t) => onTimedEvent(sender, t, newParticle, newEnvironment);
aTimer.Tick += TimerEvent;
ListOfVelocities.Add((velocity)newParticle.CurrentVelocity.Clone());
InSimulation = true;
aTimer.Start();
}
}
if you want to assign you InitialVelocity with CurrentVelocity Assign property by property. Like this below
newParticle.CurrentVelocity.AngleOfTravel = newParticle.InitialVelocity.AngleOfTravel;
newParticle.CurrentVelocity.HorizontalVelocity = newParticle.InitialVelocity.HorizontalVelocity;
newParticle.CurrentVelocity.Magnitude = newParticle.InitialVelocity.Magnitude;
newParticle.CurrentVelocity.VerticalVelocity = newParticle.InitialVelocity.VerticalVelocity;
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 following code. When I click on the button picturebox move from right to left and top to bottom. When it move to the end of the panel it again start from right to left and top to bottom. Now the problem is, after first completion of picturebox from right to left timer speed gradually increase though i set it to 200 also it seems that, this line myform.counterTop = myform.counterTop + 5; the value 5 also increase gradually. After first round, it increase a little, after second it increase little more and continues like this. Please tell me why this is happening.
namespace Spaceship_Invaders
{
public partial class Form1 : Form
{
private int invaderlanded = 0;
private int invaderstopped = 0;
private int counterfortop = -60;
private int counterforleft = 415;
private int counterTop = -60;
private int counterLeft = 415;
private bool pictureboxclicked = false;
private int timerinterval = 200;
System.Windows.Forms.Timer mytimer = new System.Windows.Forms.Timer();
public Form1()
{
InitializeComponent();
Image myImage = Image.FromFile("image/Untitled6.png");
pictureBox1.Image = myImage;
pictureBox1.Top = counterfortop;
pictureBox1.Left = counterforleft;
}
public class Spaceship
{
Form1 myform;
public Spaceship(Form1 form)
{
myform = form;
}
public void mspaceship()
{
myform.mytimer.Tick += new EventHandler(TimerEventProcessor);
myform.mytimer.Interval = myform.timerinterval;
myform.mytimer.Enabled = true;
myform.mytimer.Start();
}
private void TimerEventProcessor(Object myObject, EventArgs myEventArgs)
{
if (myform.pictureboxclicked)
{
myform.mytimer.Interval = 5;
myform.pictureBox1.Top = myform.counterTop;
//myform.pictureBox1.Left = myform.counterLeft;
myform.counterTop = myform.counterTop - 5;
if (myform.counterTop <-60)
{
//myform.pictureBox1.Enabled = false;
//myform.pictureBox1.Hide();
myform.pictureboxclicked = false;
myform.mytimer.Interval = myform.timerinterval;
myform.counterLeft = 415;
myform.counterTop = -60;
myform.mytimer.Stop();
}
} else {
if (myform.counterTop > 370 || myform.counterLeft < 1)
{
//myform.pictureBox1.Enabled = false;
//myform.pictureBox1.Hide();
myform.invaderlanded++;
myform.textBox2.Text = myform.invaderlanded.ToString();
myform.counterLeft = 415;
myform.counterTop = -60;
myform.pictureboxclicked = false;
myform.mytimer.Interval = myform.timerinterval;
myform.mytimer.Stop();
} else {
myform.pictureBox1.Top = myform.counterTop;
myform.pictureBox1.Left = myform.counterLeft;
myform.counterTop = myform.counterTop + 5;
myform.counterLeft = myform.counterLeft - 5;
}
}
}
}
private void button4_Click(object sender, EventArgs e)
{
Spaceship myspaceship = new Spaceship(this);
myspaceship.mspaceship();
}
Every time you call mspaceship(), you add another event handler to the timer.
The second time you click it, you have two event handlers which each move by 5 pixels.
Instead, you should only add the handler once.