Can't Stop The DispacherTimer - c#

I am writting some code in a wpf and I have a mouse that performs a click if the cursor stands still for a few seconds..I want to stop clicking if I open a new wpf window that i created...But it seems that dispachers doesn't stop, even if I tried almost everything...Is there any way??
public DispatcherTimer NewDispacher = new DispatcherTimer();
public DispatcherTimer NewDispacher2 = new DispatcherTimer();
public void CreateDispachers()
{
NewDispacher.Tick += new EventHandler(NewDispacher_Tick);
NewDispacher.Interval = new TimeSpan(0, 0, 0, 0, 10);
NewDispacher.Start();
NewDispacher2.Tick += new EventHandler(NewDispacher2_Tick);
NewDispacher2.Interval = new TimeSpan(0, 0, 0, 4);
NewDispacher2.Start();
}
public void NewDispacher_Tick(object sender, EventArgs e)
{
pointcur = GetCursorPosition();
}
public void NewDispacher2_Tick(object sender, EventArgs e)
{
pointdiff = GetCursorPosition();
if(form1opened==true)
{
NewDispacher.Stop();
NewDispacher = null;
NewDispacher2.Stop();
NewDispacher2 = null;
}
else if ((pointdiff.X >= pointcur.X - 5)
&& (pointdiff.X <= pointcur.X + 5)
&& (pointdiff.Y >= pointcur.Y - 5)
&& (pointdiff.Y <= pointdiff.Y + 5))
{
DoMouseClick();
pointcur.X = 0;
}
}
I make the bool Form1opened=true when the new Form is opened, but even if it gets into the if, dispachers doesn't stop...
Thanks in advance..

The fact is, Stop() *emphasized text*does*emphasized text* stop a DispatcherTimer in its tracks. So there must be an explanation elsewhere in your code. Perhaps you are restarting the timer somehow? Check when the code can execute that instantiates/starts the timers, in case it's getting called again unintentionally.

Related

Image detection optimization

I'm writing a script to automate the boring parts of a game. Essentially, I have a check boxes for different parts of the game that multiple players can use. If a checkbox its ticked then the script takes a screenshot and then if the location is available, my character is able to click the location and hops on this particular location before another player can, which looks like figure1.
Now, I have at most 18 possible locations my character can access (as long as another character is not already there.) If I have all 18 of the boxes checked, then my script will start running through all 18 of these locations until it finds an open one. Which is represented by basically a copy/paste of figure1 but adjusted in figure2.
I have a timer that kicks off every 5 seconds that checks to see if the screen has changed to check if it needs to take action. While, its not using a huge amount of CPU/memory sometimes it stops responding which isnt good. Also, every 5 seconds (which is when its performing screen checks) the power usage jumps to Very High. How can I optimize this so its more efficient? Are there better ways to check for screen changes?
--figure1--
private void Form1_Load(object sender, EventArgs e)
{
//reference picture in resource folder
ImageName = new LockBitmap(Properties.Resources.ImageName);
ImageName.LockBits();
//ImageDetection
private LockBitmap ImageName;
private void RunImageName()
{
var handle = GetWindowsHandle();
using (var screenshot = new LockBitmap(CaptureClient(handle)))
{
screenshot.LockBits();
//Extensions menthod
//screenshot.DoesImageExist(playbutton);
var location = screenshot.GetFirstLocation(ImageName);
if (location != Point.Empty)
{
var topleft = GetProcessWindowPoint(handle);
var clickpoint = new Point(topleft.X + location.X, topleft.Y + location.Y);
User32.SetCursorPos(clickpoint.X, clickpoint.Y);
User32.mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
Thread.Sleep(50);
User32.mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
}
}
}
}
private void timer1_Tick(object sender, EventArgs e)
{
//Argument
if (ImageName01.Checked)
{
RunImageName();
RunImageNameIcon();
}
}
--figure2--
private void Form1_Load(object sender, EventArgs e)
{
//reference picture in resource folder
ImageName1 = new LockBitmap(Properties.Resources.ImageName1);
ImageName1.LockBits();
ImageName2 = new LockBitmap(Properties.Resources.ImageName2);
ImageName2.LockBits();
ImageName3 = new LockBitmap(Properties.Resources.ImageName3);
ImageName3.LockBits();
}
//ImageDetection
private LockBitmap ImageName1;
private void RunImageName1()
{
var handle = GetWindowsHandle();
using (var screenshot = new LockBitmap(CaptureClient(handle)))
{
screenshot.LockBits();
//Extensions menthod
//screenshot.DoesImageExist(playbutton);
var location = screenshot.GetFirstLocation(ImageName1);
if (location != Point.Empty)
{
var topleft = GetProcessWindowPoint(handle);
var clickpoint = new Point(topleft.X + location.X, topleft.Y + location.Y);
User32.SetCursorPos(clickpoint.X, clickpoint.Y);
User32.mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
Thread.Sleep(50);
User32.mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
}
}
}
private LockBitmap ImageName2;
private void RunImageName2()
{
var handle = GetWindowsHandle();
using (var screenshot = new LockBitmap(CaptureClient(handle)))
{
screenshot.LockBits();
//Extensions menthod
//screenshot.DoesImageExist(playbutton);
var location = screenshot.GetFirstLocation(ImageName2);
if (location != Point.Empty)
{
var topleft = GetProcessWindowPoint(handle);
var clickpoint = new Point(topleft.X + location.X, topleft.Y + location.Y);
User32.SetCursorPos(clickpoint.X, clickpoint.Y);
User32.mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
Thread.Sleep(50);
User32.mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
}
}
}
private LockBitmap ImageName3;
private void RunImageName3()
{
var handle = GetWindowsHandle();
using (var screenshot = new LockBitmap(CaptureClient(handle)))
{
screenshot.LockBits();
//Extensions menthod
//screenshot.DoesImageExist(playbutton);
var location = screenshot.GetFirstLocation(ImageName3);
if (location != Point.Empty)
{
var topleft = GetProcessWindowPoint(handle);
var clickpoint = new Point(topleft.X + location.X, topleft.Y + location.Y);
User32.SetCursorPos(clickpoint.X, clickpoint.Y);
User32.mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
Thread.Sleep(50);
User32.mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
}
}
}
}
private void timer1_Tick(object sender, EventArgs e)
{
//Argument
if (ImageName01.Checked)
{
RunImageName1();
RunImageNameIcon();
}
if (ImageName02.Checked)
{
RunImageName2();
RunImageNameIcon();
}
if (ImageName03.Checked)
{
RunImageName3();
RunImageNameIcon();
}
}
Try using a background worker. When you run the computations on the same thread as the UI it creates bottlenecks which causes the UI to freeze up and sometimes do other strange stuff. Here's a link that might be useful Using a Background Worker.

wpf Multiple dispatch timer for timer application : Run multiple timer simulteniously

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.

Updating minutes in a Timer for Windows store app

I'm trying to create a timer for my windows store app,
I've been able to update secondes,but not minutes,
minutes gets its value from a combobox
What I'm doing wrong here?
public sealed partial class MainPage : Page
{
int secCount = 0;
DispatcherTimer timerCount = new DispatcherTimer();
TextBlock time = new TextBlock();
int m;
public MainPage()
{
this.InitializeComponent();
timerCount.Interval = new TimeSpan(0, 0, 0, 1, 0);
timerCount.Tick += new EventHandler<object>(timer_tick);
m = Convert.ToInt32(cMinutes.SelectedValue);
}
private void timer_tick(object sender, object e)
{
time.Text = cHours.SelectedItem + ":" + m + ":" + secCount;
timer.Children.Add(time); //timer is the main grid
secCount--;
if(secCount < 0)
{
secCount = 59;
m--;
}
}
First there is an issue in your code, you are adding the TextBlock time to the timer Grid repeatedly, and you should get an exception complaining that the TextBlock is already one of the Grid's children.
The answer to your question
You need to update cMinutes' SelectedValue or SelectedIndex.
Some enhancements:
I move the initialization of the fields timerCount and time into the MainPage's constructor, it is a good practice to initialize all the fields in one place.
Since int (secCount and m) is default to 0, you don't need to set the initial values for ints.
public sealed partial class MainPage : Page
{
int secCount;
int m;
DispatcherTimer timerCount; //declare here, initialize in constructor
TextBlock time; //declare here, initialize in constructor
public MainPage()
{
this.InitializeComponent();
time = new TextBlock();
timer.Children.Add(time); //fix: only add ONCE
//populate the Combobox
cMinutes.Items.Add(0);
cMinutes.Items.Add(1);
cMinutes.Items.Add(2);
cMinutes.SelectedIndex = 2;
m = Convert.ToInt32(cMinutes.SelectedValue);
timerCount = new DispatcherTimer();
timerCount.Interval = new TimeSpan(0, 0, 0, 1, 0);
timerCount.Tick += new EventHandler<object>(timer_tick);
timerCount.Start();
}
private void timer_tick(object sender, object e)
{
time.Text = cHours.SelectedItem + ":" + m + ":" + secCount;
secCount--;
if (secCount < 0)
{
secCount = 59;
m--;
if (cMinutes.Items.Contains(m)) //fix: update Combobox's selected value
cMinutes.SelectedValue = m;
}
}
}

WPF Dispatchertimer is not stopping, nor restarting

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);
}

How to make a thread wait until another thread is finished to start

I am using a DispatcherTimer which calls a method to execute in a different thread. I am running a simple program that does not need to really worry about inefficiencies. How do I get the UI thread to wait for the DispatcherTimer to finish while still allowing the DispatcherTimer thread to make changes to the UI?
*I understand this may be semi repetitive however the examples I have seen are case specific. Thanks
private void spinButton_Click(object sender, RoutedEventArgs e)
{
minSelTextBlock.Text = "";
Index = 0;
maxIndex = rnd.Next(40, 60);
DispatcherTimer timer;
timer = new DispatcherTimer(DispatcherPriority.Normal);
timer.Interval = TimeSpan.FromMilliseconds(60);
timer.Tick += new EventHandler(TimerTick);
timer.Start();
selPeople[x].IsCheck = false;
displayCount++;
Index = 0;
maxIndex = rnd.Next(40, 60);
timer = new DispatcherTimer(DispatcherPriority.Normal);
timer.Interval = TimeSpan.FromMilliseconds(60);
timer.Tick += new EventHandler(TimerTick);
timer.Start();
selPeople[x].IsCheck = false;
displayCount++;
displayImage2b.Source = new BitmapImage(new Uri(selPeople[0].ImgPath));
}
private void TimerTick(object sender, EventArgs e)
{
minSelTextBlock.Text = "";
x = rnd.Next(0, selPeople.Count);
while (x == temp)
{
x = rnd.Next(0, selPeople.Count);
}
if (displayCount == 0)
displayImage1a.Source = new BitmapImage(new Uri(selPeople[x].ImgPath));
if (displayCount == 1)
displayImage2a.Source = new BitmapImage(new Uri(selPeople[x].ImgPath));
if (++Index >= maxIndex)
{
((DispatcherTimer)sender).Stop();
}
Index++;
temp = x;
}
Basically I need TimerTick to get the final x value before selPeople[x].IsCheck = false, because the whole point is to remove the item that was just selected from the list.
If you want the caller method to wait for the result of the method which is called, you can use Async/Await that is available in .Net 4.5
You can do something like this:
private async void spin()
{
minSelTextBlock.Text = "";
Index = 0;
maxIndex = rnd.Next(40, 60);
DispatcherTimer timer;
timer = new DispatcherTimer(DispatcherPriority.Normal);
timer.Interval = TimeSpan.FromMilliseconds(60);
timer.Tick += new EventHandler(StartTicker);
timer.Start();
selPeople[x].IsCheck = false;
displayCount++;
Index = 0;
maxIndex = rnd.Next(40, 60);
await Ticker();
selPeople[x].IsCheck = false;
displayCount++;
displayImage2b.Source = new BitmapImage(new Uri(selPeople[0].ImgPath));
}
Private Task<void> StartTicker()
{
Task.Run<void>(()=>Ticker());
}
private void Ticker()
{
while(your condition is true)
{
minSelTextBlock.Text = "";
x = rnd.Next(0, selPeople.Count);
while (x == temp)
{
x = rnd.Next(0, selPeople.Count);
}
if (displayCount == 0)
displayImage1a.Source = new BitmapImage(new Uri(selPeople[x].ImgPath));
if (displayCount == 1)
displayImage2a.Source = new BitmapImage(new Uri(selPeople[x].ImgPath));
if (++Index >= maxIndex)
{
break;
}
Index++;
temp = x;
Thread.Sleep(60);
}
}
Instead of Timer I have used a While Loop and Thread.Sleep() which is the same as your timer.
If you want to learn about async/await I really recommend this
Bye the way I haven't compiled this code. so it might have some syntax or other errors.

Categories