I have tried this on Win7 and Win10. On Win7 works as I thought, Tick is called every 100ms. But on win10, the Tick is called 2 times at run, and then stops until I do a mouseover the app, which fires anouther Tick for 1 time. This is weird.
I'm using System.Windows.Threading.
The code is all in code-behind to test it and this is all to keep it simple:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
TimerGeneral(true);
}
public DispatcherTimer timer = new DispatcherTimer();
int s;
public void TimerGeneral(bool estado)
{
timer.Interval = TimeSpan.FromMilliseconds(100);
if (estado && !timer.IsEnabled) { timer.Tick += timer_Tick; timer.Start(); }
else if (!estado && timer.IsEnabled) { timer.Stop(); }
}
public void timer_Tick(object sender, EventArgs e)
{
Debug.WriteLine("tick" + s++);
}
}
I'm a little lost why Win10 works different, sorry.
Keep in mind, that when instantiating DispatcherTimer using the default constructor (as you did), the timer's Dispatcher will by default execute with DispatcherPriority.Background! Hence the high latency.
Specify a higher priority by using the appropriate constructor:
var dispatcherTimer = new DispatcherTimer(DispatcherPriority.Normal, Application.Current.Dispatcher)
This should fix your issue.
In case the latency is still too high, try DispatcherPriority.Send (use with care).
If an operation is posted to a Dispatcher at DispatcherPriority.Send, the operation bypasses the queue and is immediately executed.
Depending on the timer interval and workload, the DispatcherPriority should be as low as possible to prevent the UI from becoming sluggish.
Alternatively, if Timers.Timer or any other timer is working better for you, then just use it. You can execute the UI relevant code using Application.Current.Dispatcher.Invoke(Action) or Application.Current.Dispatcher.InvokeAsync(Action).
Related
Goal: To be able to find point(X,Y) of element on windows desktop application which been clicked without performing click itself.
Not working solution
I've added mousekeyhook Nuget package to my .net core WPF application, it working fine ( when click and event raising with correct position), but each time that program hit breakpoint( for specific below example - at M_Events_MouseDown method) the mouse starts to lag for about 20 seconds.
Also i have found that in WinForms application it works smoothly
MouseKeyHook implementation:
public partial class MainWindow : Window
{
private IKeyboardMouseEvents m_Events;
public MainWindow()
{
InitializeComponent();
SubscribeGlobal();
}
private void SubscribeGlobal()
{
Unsubscribe();
Subscribe(Hook.GlobalEvents());
}
private void Subscribe(IKeyboardMouseEvents events)
{
m_Events = events;
m_Events.MouseDown += M_Events_MouseDown;
}
private void M_Events_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
Console.WriteLine($"Mouse down :{e}");
}
private void Unsubscribe()
{
if (m_Events == null)
return;
m_Events.MouseDown -= M_Events_MouseDown;
}
}
This is a known issue and low-level hook behavior by design.
When you hook into the mouse event processing chain, your code is one of many other processors. Every hooked piece of code has a possibility to suppress or modify further processing. Nevertheless, there is a time limit to do so. If you set a breakpoint, windows call your code, your code does not respond, a timeout occurs and it starts over.
See a similar question for details. The second answer with more upvotes is the better one.: Low level mouse hook - mouse freeze on breakpoint
I know normally one is not supposed to touch UI elements from threads other than the UI thread, but I am new to WPF and I am wondering if my current working implementation can be improved.
I have an application that is comprised solely of a notification tray icon, and I want to update that icon from a background thread.
Here is my Program.cs entry point:
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
using (IconHandler notify = new IconHandler())
{
notify.Display();
Application.Run();
}
}
}
This is my IconHandler.cs notification icon handler class:
class IconHandler : IDisposable
{
NotifyIcon ni;
public IconHandler()
{
ni = new NotifyIcon();
}
public void Display()
{
ni.MouseClick += new MouseEventHandler(ni_MouseClick);
ni.Icon = Resources.icon1;
ni.Visible = true;
new Thread(new ThreadStart(UpdateIcon)).Start();
}
public void UpdateIcon()
{
while (true)
{
// reference ni directly, it updates fine
}
}
public void Dispose()
{
ni.Dispose();
}
void ni_MouseClick(object sender, MouseEventArgs e)
{
// something useful
}
}
Is there anything blatantly incorrect about this? It seems a bit fishy to me - it was just my first attempt. It seems to work for what I want to do, does anyone have any suggestions for a better implementation? Will I run into lifecycle issues with this setup?
Is there anything blatantly incorrect about this? It seems a bit fishy to me - it was just my first attempt. It seems to work for what I want to do, does anyone have any suggestions for a better implementation? Will I run into lifecycle issues with this setup?
To begin with NotifyIcon is not a WPF control, but comes from the Windows Forms namespace. As such it has normal C# properties (e.g. Icon, Visible) meaning you have been able to alter the icon property in the non-UI thread without an exception being raised. If you had used a WPF controls then they have Dependency Properties and direct manipulation of Dependency Properties outside of the UI thread will cause an exception to be raised.
Will I run into lifecycle issues with this setup?
You've currently NOT created a WPF window or WPF controls. If your application develops such that you start using WPF and the UpdateIcon method is expanded to do more than you currently do and access these WPF objects then yes you will need a strategy to deal with the updates from non-UI threads.
You can hide some of this cross-threaded access using some helper methods.
Example 1 If your strategy becomes referencing WPF controls programmatically from the background thread then you can use a helper method such as this.
It first checks if the call is on the UI thread, if so then it updates the control directly, otherwise it will schedule that the method (itself) be called from the UI thread at a later point in time.
I've used BeginInvoke here so that the background thread can continue before the UI thread has actually called the method. If you want to block the background thread then use Invoke instead.
public void UpdateLabel(Label control, string text)
{
if (Application.Current.Dispatcher.CheckAccess())
control.Content = text;
else
Application.Current.Dispatcher.BeginInvoke(new System.Action(() => UpdateLabel(control, text)), DispatcherPriority.Normal);
}
Example 2
If your strategy uses Events raised on the background thread to update the WPF controls programmatically then you can hide some of the cross-threading calls as part of raising the event, leaving the WPF update routine quite clean and simple to read.
Any event handlers of this event can be coded knowing that the call will be made from the UI thread, so no threading issues.
public void OnRaiseEvent(EventHandler handler, EventArgs args)
{
if (handler != null)
{
if (Application.Current.Dispatcher.CheckAccess())
handler(sender, new PropertyChangedEventArgs(propName));
else
Application.Current.Dispatcher.BeginInvoke(new System.Action(() => handler(sender, args)), DispatcherPriority.Normal);
}
}
Example 3
If your future strategy fully utilizes the benefits of WPF with Binding (as opposed to programmatically updating your WPF controls), then you can embed the cross-threading code into the data-bound objects.
If for example your XAML databinds to the MyProperty property of an instance of the MyDataClass class and that class implements the INotifyPropertyChanged interface you can put the cross-threading code in the data class making it possible to update the data from any thread. Here is the example of the class:-
public class MyDataClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _myProperty;
public string MyProperty { get { return _myProperty;} set { PropertyChanged.SetValueAndNotify(this, ref _myProperty, value); } }
}
This class utilizes the SetValueAndNotify extension method on the PropertyChanged event. It is in here we hide the cross-threading code to simplify other parts of the code. Here's the definition of this extension method.
public static class PropertyChangedExtension
{
public static void SetValueAndNotify<T>(this PropertyChangedEventHandler handler, object sender, ref T destination, T source, [CallerMemberName] string propName = "notset")
{
// Is the new value different from the previous value? If there is no difference then there is nothing more to do
if (Equals(destination, source))
return;
// If we got to this point then the new value is different from the old value, so lets make the assignemnt and raise the property changed event
destination = source;
if (handler != null)
{
if (Application.Current.Dispatcher.CheckAccess())
handler(sender, new PropertyChangedEventArgs(propName));
else
Application.Current.Dispatcher.BeginInvoke(new System.Action(() => handler(sender, new PropertyChangedEventArgs(propName))), DispatcherPriority.Normal);
}
}
}
The above example uses the [CallerMemberName] attribute from C#5 to remove any typing errors in supplying the property name for the INotifyPropertyChanged arguments. If you are not using the latest then you will need to modify the getter and setter as follows:-
public string MyProperty { get { return _myProperty;} set { PropertyChanged.SetValueAndNotify(this, ref _myProperty, value, "MyProperty"); } }
You must always update UI from UI thread only, however, you can schedule some work on UI thread from background thread using dispatcher
public void Display()
{
ni.MouseClick += new MouseEventHandler(ni_MouseClick);
ni.Icon = Resources.icon1;
ni.Visible = true;
new Thread(new ThreadStart(UpdateIcon)).Start();
}
public void UpdateIcon()
{
while (true)
{
//do some long running work
Application.Current.Dispatcher.Invoke(()=>{
//update ui
});
}
}
But if you don't have long running work and you just want to do something periodically, you should use DispatcherTimer instead of loop in background thread.
The while(true) loop in your code will cause heavy CPU/resource usage. maybe add e.g. Thread.Sleep(1000) into the loop to allow for a break between updates.
The best usage of background threads is to perform the long-running work (e.g. communication with server/DB) on the background thread and once the thread completes, have the UI thread update the UI.
With BackgroundWorker:
var worker = new BackgroundWorker();
worker.DoWork += (sender, args) =>
{
// long running work
};
worker.RunWorkerCompleted += (sender, args) =>
{
// Update UI
};
worker.RunWorkerAsync();
async/await pattern:
public async void DoWork()
{
// Do long running task
var data = await Task.Run(() => new object());
// Update UI here
}
TaskFactory:
Task.Factory.StartNew(() => new Object()).ContinueWith(task => MessageBox.Show(task.Result.ToString()), TaskScheduler.FromCurrentSynchronizationContext());
If the UI needs to update on a constant loop, maybe use a timer to restart the process on a regular basis. This will save your CPU from taking a pounding.
I want to run integration UI tests on my WPF application, and I'm not sure how to detect when the current test has finished so that I can proceed to the next one.
Simplifying, suppose I have a button on my window. When the button is clicked I disable it, I modify the model, and I re-enable the button. Once it detects that the model has changed, WPF changes the view on the screen.
Now I want to run a test that simulates clicking the button again and again. To click the button I’ll use automation, as described in this SO question. But how do I know when the work is finished and the display updated, so as to "click" the button again? Do I hook the botton’s IsEnabledChanged, or is there some global indication that the current cycle of processing has finished?
Edit: What was missing in my description is that I want the user to see the interim results on the screen. For example, if the test has 10 phases I want the user to see something like a Step Counter label with values 1 .. 10 appearing on the screen, and not just the number changing immediately from 1 to 10. See my answer below.
how do I know when the work is finished and the display updated, so as to "click" the button again?
According to your description, you said When the button is clicked I disable it, I modify the model, and I re-enable the button.
Therefore, I can only assume that when the model has changed, the Button will be re-enabled. So you could either attach a handler to the model's NotifyPropertyChanged event, or as you suggested, add a handler for the IsEnabledChanged event.
Here is how I managed to get it working. This might be trivial - I'm a novice with GUI. I'm just posting it here in the hope it'll help other novices like me :)
Anyhow, what I used is a two button solutions: Test and Step. Test starts the testing sequence, Step runs each step of the tests. The Step buttons interact with an Integration Tester By Steps helper.
The helper receives an Init with the Number Of Commands as parameter, (currently the helper generates random commands by itself, so it just needs to know how many commands to generate). The helpe provides a Step method to execute the next command, and a Needs More Steps property to indicate whether testing should continue.
The helper derives form INotifyPropertyChanged and has a Counter dependency property that is displayed on the main window.
The states of the Test and Step buttons are controlled by three helper methods: SetButtonsFor_OutsideTesting, SetButtonsFor_InsideTestingOutsideAnyStep and SetButtonsFor_InsideTestingInsideAStep.
First, I verified that everything is working manually, and then I added a timer and automated the process using the Stack Overflow suggestions on how to programmatically click a button in WPF and how to make a WPF Timer Like C# Timer.
Now, here's the Main Window's code:
private void Test_Click(object sender, RoutedEventArgs e)
{
SetButtonsFor_InsideTestingOutsideAnyStep();
RunTheTestBySteps();
}
public readonly IntegrationTesterBySteps _integrationTesterBySteps =
new IntegrationTesterBySteps();
void RunTheTestBySteps()
{
SetButtonsFor_InsideTestingOutsideAnyStep();
IntegrationTesterBySteps.Init(10);
StartTheTimer();
}
private void StartTheTimer()
{
DispatcherTimer = new DispatcherTimer();
DispatcherTimer.Tick += DispatcherTimer_Tick;
DispatcherTimer.Interval = new TimeSpan(0, 0, 1);
DispatcherTimer.Start();
}
private void StopTheTimer()
{
DispatcherTimer.Stop();
DispatcherTimer.Tick -= DispatcherTimer_Tick;
}
private DispatcherTimer DispatcherTimer { get; set; }
private void DispatcherTimer_Tick(object sender, EventArgs e)
{
if (!BtnStep.IsEnabled) return;
ClickTheStepButton();
CommandManager.InvalidateRequerySuggested();
}
private void BtnStep_Click(object sender, RoutedEventArgs e)
{
SetButtonsFor_InsideTestingInsideAStep();
IntegrationTesterBySteps.Step();
if (this.IntegrationTesterBySteps.NeedsMoreSteps)
SetButtonsFor_InsideTestingOutsideAnyStep();
else
{
SetButtonsFor_OutsideTesting();
StopTheTimer();
}
}
private void ClickTheStepButton()
{
var peer = new ButtonAutomationPeer(BtnStep);
var invokeProv = peer.GetPattern(PatternInterface.Invoke)
as IInvokeProvider;
if (invokeProv != null)
invokeProv.Invoke();
}
void SetButtonsFor_InsideTestingInsideAStep()
{
BtnTest.IsEnabled = false;
BtnStep.IsEnabled = false;
}
void SetButtonsFor_InsideTestingOutsideAnyStep()
{
BtnTest.IsEnabled = false;
BtnStep.IsEnabled = true;
}
void SetButtonsFor_OutsideTesting()
{
BtnTest.IsEnabled = true;
BtnStep.IsEnabled = false;
}
If I use Monitor.Enter/Exit (through the c# lock syntax) in a WPF application, can the dispatcher cause re-entrance?
In the sample below, presuming OnTextChanged is called when the text in a textbox changes, could the call to _worker.RunWorkerAsync() be called incorrectly?
public class SomeClass
{
private object _locker = new object();
private bool _running = false;
private BackgroundWorker _worker;
public void SomeClass()
{
// initialize worker...
}
void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
lock (_locker)
_running = false;
}
void _worker_DoWork(object sender, DoWorkEventArgs e)
{
// ... do something time consuming ...
}
private void OnTextChanged()
{
lock(_locker)
{
if (!_running)
{
_worker.RunWorkerAsync();
_running = true;
}
}
}
}
I believe it's possible, but I've not been able to reproduce this. Does WPF somehow prevent the dispatcher from invoking waiting tasks when waiting on monitor?
Not sure what you fear. Both OnTextChanged and RunWorkerCompleted run on the UI thread. It won't be re-entrant, you don't need the lock either. Either method can only start running when the UI thread is idle, pumping the message loop.
While not directly related to your question, you could run into register caching issues if you don't mark _running as volatile.
Actually this isn't strictly true, as you are not using a double-checked lock. I've left the information related to volatile there anyway, for your reference.
I think I need some clarifications regarding WPFs Dispatcher.Invoke and Dispatcher.BeginInvoke usage.
Suppose I have some long running 'work' code like such that is invoked on the press of a button in a simple WPF application:
longWorkTextBox.Text = "Ready For Work!";
Action workAction = delegate
{
Console.WriteLine("Starting Work Action");
int i = int.MaxValue;
while (i > 0)
i--;
Console.WriteLine("Ending Work Action");
longWorkTextBox.Text = "Work Complete";
};
longWorkTextBox.Dispatcher.BeginInvoke(DispatcherPriority.Background, workAction);
This code is locking up my user interface while the workAction is being performed. This is because Dispatcher invokes always run on the UI thread, right?
Assuming this, what is the best practice for configuring my dispatcher to execute the workAction in a separate thread from my UI? I know I can add a BackgroundWorker to my workAction to prevent my UI from locking as such:
longWorkTextBox.Text = "Ready For Work!";
Action workAction = delegate
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate
{
Console.WriteLine("Starting Slow Work");
int i = int.MaxValue;
while (i > 0)
i--;
Console.WriteLine("Ending Work Action");
};
worker.RunWorkerCompleted += delegate
{
longWorkTextBox.Text = "Work Complete";
};
worker.RunWorkerAsync();
};
longWorkTextBox.Dispatcher.BeginInvoke(DispatcherPriority.Background, workAction);
Is there any more elegant ways of doing this besides using the BackgroundWorker? I've always heard that the BackgroundWorker is quirky, so I am curious to know of some alternatives.
I honestly think the BackgroundWorker is the most elegant solution for this. I cannot think of a simpler way to do it.
Me too don't like BackgroundWorker.
A simple alternative can be something like:
using System;
using System.Threading;
using System.Windows;
namespace Sample
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
longWorkTextBox.Text = "Ready For Work!";
}
private void startButton_Click(object sender, RoutedEventArgs e)
{
new Thread(Work).Start();
}
void Work()
{
longWorkTextBox.Dispatcher.BeginInvoke((Action)(() => { longWorkTextBox.Text = "Working..."; }));
Console.WriteLine("Starting Work Action");
int i = int.MaxValue;
while (i > 0)
i--;
Console.WriteLine("Ending Work Action");
longWorkTextBox.Dispatcher.BeginInvoke((Action)(() => { longWorkTextBox.Text = "Work Complete"; }));
}
}
}
Easy, not?
Charlie's answer is what you are looking for, really.
However, if it's possible you might look at whether or not you can parcel up your work so that the individual units of work are small and don't affect the UI as much. This would allow you to just use the Dispatcher directly. There is a good example of this on the WPF Threading page: https://msdn.microsoft.com/en-us/library/ms741870%28v=vs.100%29.aspx
As its name indicates it will execute in the Background so you don't need to instantiate it with the Dispatcher. Plus if you want this code to run into a WP7 the BeginInvoke does not get the background parameter.
My recommendation is to create the BackgroundWorker as:
BackgroundWorker worker = new BackgroundWorker;
And then create the handlers for the events:
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;
worker.DoWork +=new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted +=new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.ProgressChanged +=new ProgressChangedEventHandler(worker_ProgressChanged);
And finally you call:
bkwkPlayingLoop.RunWorkerAsync();
It is a big temptation to use the Dispatcher from inside the DoWork but instead call worker.ReportProgress() and handle the UI from there. You will otherwise face some inconsistencies with the firing of termination events.
Tasks are easier to use than Background workers, do more things, have fewer issues and were pretty much created so Background Workers didn't need to be used anymore...