I've written a simple schedule app which calculates 10 nearest scheduled bus arrivals depending on current time, and displays them in 10 textViews. Now what I need is to have the whole process repeat over and over every second and refresh the data.
Below is the class that is loaded after this delegate:
button1.Click += delegate
{
StartActivity(typeof(Schedule));
FullSchedule.MMain("route1_1_0");
};
namespace AndroidApplication7
{
[Activity(Label = "My Activity")]
public class Schedule : Activity
{
public System.Timers.Timer _timer;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Schedule);
TextView textView0 = FindViewById<TextView>(Resource.Id.textView0);
TextView textView1 = FindViewById<TextView>(Resource.Id.textView1);
TextView textView2 = FindViewById<TextView>(Resource.Id.textView2);
TextView textView3 = FindViewById<TextView>(Resource.Id.textView3);
TextView textView4 = FindViewById<TextView>(Resource.Id.textView4);
TextView textView5 = FindViewById<TextView>(Resource.Id.textView5);
TextView textView6 = FindViewById<TextView>(Resource.Id.textView6);
TextView textView7 = FindViewById<TextView>(Resource.Id.textView7);
TextView textView8 = FindViewById<TextView>(Resource.Id.textView8);
TextView textView9 = FindViewById<TextView>(Resource.Id.textView9);
TextView textView10 = FindViewById<TextView>(Resource.Id.textView10);
textView1.Text = FullSchedule.T[0];
textView2.Text = FullSchedule.T[1];
textView3.Text = FullSchedule.T[2];
textView4.Text = FullSchedule.T[3];
textView5.Text = FullSchedule.T[4];
textView6.Text = FullSchedule.T[5];
textView7.Text = FullSchedule.T[6];
textView8.Text = FullSchedule.T[7];
textView9.Text = FullSchedule.T[8];
textView10.Text = FullSchedule.T[9];
_timer = new System.Timers.Timer();
_timer.Interval = 1000;
_timer.Elapsed += OnTimedEvent;
_timer.Enabled = true;
}
private void OnTimedEvent(object sender, System.Timers.ElapsedEventArgs e)
{
RunOnUiThread(() => FullSchedule.MMain(FullSchedule.nname));
RunOnUiThread(() => StartActivity(typeof(Schedule)));
}
}
}
But there are two problems:
Every second it updates the view slews from the side as if it was opened (quite logical but I'm not quite sure of a different way of doing it).
After 5-10 seconds the app freezes and the screen is just blank.
I'll really appreciate any suggestions to how this updating can be accomplished.
Dmetrey.
It looks like you're creating a new activity on every timer interval, but at no point do you call Finish(). So you create an activity. 1 second later you create a second. 1 second later both activities create another one (4 activities total), 1 second later 8 activities, etc. Do you mean to do this?
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
here is what i want to do.
i'm using Xamarin Android and trying to make a 24hour count down timer.
the timer text should be updated every second
when the app relaunches it should continue with saved time.
DateTime timeStartedCountDown;
timer should calculate time from one point. (not runtime delay)
eg) what i want =
DateTime timeStartedCountDown;
every second
DisplayLeftTime(24 + (timeStartedCountDown - currentTime)) ? some like this
not what i want =
int timeElapsed;
every second
timeElapsed += 1;
text.Text = twentyFourHoursSec - timeElapsed
i'm not familiar with time & Threading sorry..
ps. android java code is fine!
This starts a timer the first time you open the app.
It recalls the startTime by using ISharedPreferences. And updates the date each second in the Thread.
public class MainActivity : Activity
{
DateTime startTime = DateTime.Now;
Thread thread;
protected override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences (this);
ISharedPreferencesEditor editor = prefs.Edit ();
long memStartTime = prefs.GetLong ("startTime", 0);
if (memStartTime != 0) {
startTime = new DateTime (memStartTime);
} else {
editor.PutLong ("startTime", startTime.Ticks);
editor.Apply();
}
TimerUpdate ();
}
void TimerUpdate () {
if (thread == null) {
thread = new Thread (delegate () {
while (true) {
Thread.Sleep (1000);
DateTime curTime = DateTime.Now;
Console.WriteLine (curTime - startTime);
//Update your on screen textview.
}
});
thread.Start ();
}
}
}
Read multiple stackoverflow, codeproject solution, could not integrate to my problem.
Have a datagrid in a usercontrol which is loaded in a window. Each DataRow in the DataGrid represents a timer setting.
Like:
timer name : Test 1 , Timer : 1h 3m
timer name : Test 2 , Timer : 2h 2m
timer name : Test 3 , Timer : 3h 1m
Selecting a row, clicking on the button Start, Starts the timer of that row. And with dispatcher tick event, it updates the grid I have done till this. Now I have to start another(or two or ...) timer which will do the same at the same time. I am stuck on this. Let me share what I have tried!
btnStartClickEvent in mainwindow.xaml.cs
if (btnStart.Content.ToString() == "Start")
{
if (_AUC == ActiveUserControl.Grid)
{
runningRow = (TaskGridData)_TG.dgEmployee.SelectedItem;
if (runningRow != null)
{
currentlyRunningID.Add(runningRow.ID);
btnStart.Content = "Stop";
//worker.RunWorkerAsync(runningRow);
StartTimer(runningRow);
}
}
}
else if (btnStart.Content.ToString() == "Stop")
{
btnStart.Content = "Start";
StopTimer();
}
private DateTime TimerStart { get; set; }
private void StartTimer(TaskGridData tgd)
{
dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 1, 0);
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
TimerStart = DateTime.Now;
dispatcherTimer.Start();
//worker.RunWorkerAsync();
//string etime = DateTime.Now.Second.ToString();
}
private void StopTimer()
{
dispatcherTimer.Stop();
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
var currentValue = DateTime.Now - TimerStart;
runningRow.Duration = DurationValueToString(currentValue);
temp = (List<TaskGridData>)_TG.dgEmployee.ItemsSource;
foreach (TaskGridData item in temp)
{
if (item.ID == runningRow.ID)
{
item.Duration = DurationValueToString(DurationStringToVlaue(item.Duration) - DurationStringToVlaue(runningRow.Duration));
break;
}
}
//_TG.dgEmployee.ItemsSource = null;
//_TG.dgEmployee.ItemsSource = temp;
Thread NewThreadforStartProcessAfterTraining = new Thread(() => UpdateGrid());
NewThreadforStartProcessAfterTraining.IsBackground = true;
NewThreadforStartProcessAfterTraining.SetApartmentState(ApartmentState.STA);
NewThreadforStartProcessAfterTraining.Start();
}
private void UpdateGrid()
{
this.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
{
_TG.dgEmployee.ItemsSource = null;
_TG.dgEmployee.ItemsSource = temp;
}));
}
I know this code is for single timer. If I click a 2nd row and try to start timer, then it gets error in tick event, running row is found null.
I am wondering how can I keep this code and make it work for multiple timer. May be multithreading. A guide to do that, will be very helpful.
Thread NewThreadforStartProcessAfterTraining = new Thread(() => UpdateGrid());
NewThreadforStartProcessAfterTraining.IsBackground = true;
NewThreadforStartProcessAfterTraining.SetApartmentState(ApartmentState.STA);
NewThreadforStartProcessAfterTraining.Start();
All the above part where you start a new STA thread is unneeded and wrong in this context, since you can't update the visual tree in this way.
You can find a correct example of using a STA thread in one of my previous answers: https://stackoverflow.com/a/42473167/6996876
Try to understand the concept of thread affinity in WPF.
You simply need an UpdateGrid() where you have to delegate UI work to the dispatcher.
Furthermore, passing an argument to the Tick event is already explained here: https://stackoverflow.com/a/16380663/6996876
In your case you may want to change the current unique runningRow so that it's passed to the event instead.
I have started developing a quiz app that will have a 60 second count down for each question. I searched other issues but could not find my specific issue. When the first question is displayed the screen dsplays "60" and the countdown proceeds normally. However, when the second questions is generated (after a button click submit) the counter starts again, but this time uses 2 second intervals. Then when the third question generates after a click, it counts down in 3 second intervals! I then noticed that the timer display starts 1 second less in each question. (ex Question 1 starts with 60, Question 2 starts with 59......)
This is my first time using DispatcherTimer so I'm learning as I go. My goal is for the timer to always countdown in 1 second intervals.
public sealed partial class QuickPage : Page
{
DispatcherTimer timeLeft = new Dispatcher();
int timesTicked = 60;
public void CountDown()
{
timeLeft.Tick += timeLeft_Tick;
timeLeft.Interval = new TimeSpan(0,0,0,1);
timeLeft.Start();
}
public void timeLeft_Tick(object sender, object e)
{
lblTime.Text = timesTicked.ToString();
if (timesTicked > 0)
{
timesTicked--;
}
else
{
timeLeft.Stop();
lblTime.Text = "Times Up";
}
}
}
I then use a button click where if th user is right:
timeLeft.Stop();
timesTicked = 60
QuestionGenerator();
The Question Generator fucntion looks like this:
private void QuestionGenerator()
{
CountDownTimer();
if (iAsked < 6)
{
//Code to generate random question
}
}
Do not subscribe to the DispatcherTimer every time you call CountDown.
DispatcherTimer timeLeft;
int timesTicked = 60;
public QuickPage()
{
timeLeft = new Dispatcher();
timeLeft.Tick += timeLeft_Tick;
timeLeft.Interval = new TimeSpan(0,0,0,1);
}
private void QuestionGenerator()
{
timeLeft.Start();
if (iAsked < 6)
{
//Code to generate random question
}
}
How can I create a small menu which pop-ups next to cursor in WPF with C#. This menu will work out of the application window. For example;
I move my cursor and stop it on the desktop. When it stops, there will be a small menu which is just next to the cursor and show up.
Thanks
The CODE:
static System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();
public void TimerEventProcessor(Object myObject, EventArgs myEventArgs)
{
big.Visibility = Visibility.Hidden;
myTimer.Stop();
}
public void TimerEventProcessor2(Object myObject, EventArgs myEventArgs)
{
big.Visibility = Visibility.Visible;
myTimer.Stop();
}
public MainWindow()
{
InitializeComponent();
// Sets the timer interval to 5 seconds.
myTimer.Interval = 5000;
myTimer.Start();
myTimer.Tick += new EventHandler(TimerEventProcessor);
myTimer.Start();
myTimer.Tick += new EventHandler(TimerEventProcessor2);
}
EDIT2
This is the part of the code. I created another dispatchertimer whish has a name hidingtimer. I defined the time as 3 seconds as you see on the code. And this timer calls deneme_Tick then I do the same things as HideWindow() in your code.
timer.Interval = new TimeSpan(0, 0, 0, 1);
timer.Tick += (sd, args) =>
{
movingCount++;
if (movingCount >= menuShowDelay)
{
this.Visibility = System.Windows.Visibility.Visible;
mouse.Enabled = false;
timer.Stop();
this.Left = mouseLeft;
this.Top = mouseTop;
this.Topmost = true;
hidingtimer.Interval = new TimeSpan(0, 0, 0, 3);
hidingtimer.Start();
hidingtimer.Tick += new EventHandler(deneme_Tick);
movingCount = 0;
}
};
(sorry for my bad english)
This is how I would do it:
Create your menu in WPF any way you want (it could be a real menu or a listbox, buttons on a stackpanel, etc).
Set your WindowStyle to None.
To detect mouse movement and position you could use this library
Write some logic to show/hide the window on the mouse position (with a timer to detect when the mouse isn't moving for X seconds)
If you need more details on how to acomplish those steps, let me know :)
EDIT 1
You can use the library to detect mouse movement like this:
mouse = new MouseKeyboardActivityMonitor.MouseHookListener(new GlobalHooker());
mouse.MouseMove += (sd, args) =>
{
movingCount = 0;
mouseLeft = args.X; //set the window.left to mouseLeft before showing it
mouseTop = args.Y; //set the window.top to mouseTop before showing it
};
mouse.Enabled = true;
I'll just have a crack, have a look here,
http://www.a2zdotnet.com/View.aspx?Id=92
If possible add a context menu to your main window, and then make it appear programatically like this,
Show menu programmatically in WPF
Use a timer to make it happen after 1 second.
Whether it will appear where the cursor is or not I am unsure.