How can the 'fling/flick scrolling' be disabled in CefSharp.Wpf? - wpf

Is there a way to disable the 'touch fling scrolling' behaviour in CefSharp.Wpf (or potentially via Cef, Chromium, etc)?
I appreciate it's an unusual request as touch fling scrolling is a great feature. But unfortunately, I need to integrate with a dodgy touch screen hw/driver which works nicely for drag.. but fails miserably when flick scrolling as it consistently 'over scrolls'. e.g. a gentle flick on the screen causes the page content to scroll multiple pages (instead of just a few lines).

There's no CefSharp/Cef/Chromium flag or public method available to cancel Chromium's fling behavior.
Fortunately though, Chromium does internally cancel the fling behavior under certain scenarios (refer Chromium's fling_controller.cc). One such scenario is a user touch down event.
So the trick is to simulate a touch down cancel event pair. Because CefSharp doesn't offer a 'post touch down' event for users to implement the logic (i.e. too much of an edge case), the easiest way is to implement the feature via a derived class.
Here's a complete example (with dependency property binding) in case it helps anyone else look for the same solution..
public class ChromiumWebBrowserEx : ChromiumWebBrowser
{
public static readonly DependencyProperty IsFlingDisabledProperty = DependencyProperty.Register("IsFlingDisabled", typeof(bool), typeof(ChromiumWebBrowserEx));
public bool IsFlingDisabled
{
get => (bool) GetValue(IsFlingDisabledProperty);
set => SetValue(IsFlingDisabledProperty, value);
}
protected override void OnTouchUp(TouchEventArgs e)
{
base.OnTouchUp(e);
if (IsFlingDisabled)
CancelFling(e);
}
private void CancelFling(TouchEventArgs e)
{
// cancel the fling by creating a pseudo touch down followed by a cancellation
var touchPoint = e.GetTouchPoint(this);
if (touchPoint.Action == TouchAction.Up)
{
var touchEvent = new TouchEvent
{
Id = e.TouchDevice.Id,
X = (float) touchPoint.Position.X,
Y = (float) touchPoint.Position.Y,
PointerType = PointerType.Touch,
Modifiers = WpfExtensions.GetModifierKeys(),
Type = TouchEventType.Pressed
};
GetBrowser().GetHost().SendTouchEvent(touchEvent);
touchEvent.Type = TouchEventType.Cancelled;
GetBrowser().GetHost().SendTouchEvent(touchEvent);
}
}
}

Related

Mouse freezing/lagging when hit breakpoint

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

WPF NotifyIcon From Background Thread

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.

Integration Testing of WPF GUI: How do I identify that current work was finished

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

C# checkedlistbox differentiate between ItemCheck via code and mouse click

I'm using C# VS2008, WinForm application
I have a checkedlistbox control on my form (win-form application)
In the code I check some items in checkedlistbox using the SetItemChecked(index, false) method and it raise the event ItemCheck.
I also allow the user to check items in that checkedlistbox and it also raise the event ItemCheck when the user check or uncheck an item.
How can I find in the ItemCheck event how this event occur (via code or via user keyboard/mouse input)?
Thanks.
I think that there is no a simple way to differentiate the situation using code.
The only thing that comes to mind is through the use of a global form variable:
public class Form1:Form
{
bool _isCodeClick = false;
.....
// Somewhere in your code
_isCodeClick = true;
checkedListBox1.SetItemChecked(index, true);
_isCodeClick = false;
.....
private void CheckedListBox1_ItemCheck(Object sender, ItemCheckEventArgs e)
{
if(_isCodeClick == true)
{
// Do processing for click by code
}
else
{
// Do processing for click by user
}
}
}
If you go for this solution remember to take additional steps to correctly trap exceptions that could bypass the reset of the global variable to the false state.
Probably using advanced manipulation of keyboard and mouse events you could reach a reasonable way to identify what has caused the ItemCheck event, but sometime some solutions are too complex and not worth it.
EDIT: Reviewing my answer I feel the need to add a little change to reduce the maintaining problems that this esponse implies.
The code that set the boolean variable and call the SetItemChecked should be encapsulated in a separate function like this
private void SetItemCheckedFromCode(int index, bool toSet)
{
try
{
_isCodeClick = true;
checkedListBox1.SetItemChecked(index, true);
}
finally
{
_isCodeClick = false;
}
}

wpf detect open window

In my WPF app (csharp) I have an event handler that when triggered will open a new window (window B) of the application and display some data. However, when the event is triggered again, if the new window (window B) is still open, I don't want to spawn another instance of window B but just update the data being displayed in the current instance. So the question is: How to detect if window B is already and only open if it is not already, otherwise just update the data?
I found the Application.Current.Window collection but somehow that isn't working for me yet. Ideas?
You could create a LoadWindow() method in WindowB that you can call to load (or refresh) the data & that will work regardless of if the window is already open or not. Have it take a delegate to call when this window gets closed:
private Action ParentCallbackOnClose;
public void LoadWindow( Action parentCallbackOnClose ) {
// load the data (set the DataContext or whatever)
ParentCallbackOnClose = parentCallbackOnClose;
// Open the window and activate/bring to the foreground
Show( );
Activate( );
}
and have your window closed event call the close delegate:
private void WindowClosed( object sender, EventArgs e ) {
ParentCallbackOnClose.Invoke( );
}
Now, from your class that opens Window B, have it hold onto that instance it opens, so that if WindowB is already open when someone tries to reload it, it just calls LoadWindow on the existing instance. Something like...
private WindowB WinB;
private void LoadWindowB(Content content)
{
if (WinB == null ){
WinB = new WindowB( );
}
WinB.LoadWindow(content, WindowBClosed);
}
And then you can just have it null out WinB on that close callback so if WinB is closed, then the next time LoadWindowB() is called it will create a new instance of it:
private void WindowBClosed( ){
WinB = null;
}
Since this is the first link Google listed, which posted several years ago, for a solution to check if a Window is already open, I'll post my answer, for others, which I find easier to implement. The ChildWindow is only called from MainWindow so no other Window will need to do any checks.
private void OpenChildWindow()
{
if (this.OwnedWindows.OfType<ChildWindow>().Count() > 0)
{
ChildWindow Win = this.OwnedWindows.OfType<ChildWindow>().First();
Win.Activate();
}
else
{
ChildWindow Win = new ChildWindow();
Win.Owner = this;
Win.Show();
}
}
There is an old school way to do this using an interface. I see this in Java a lot as a way to compensate for not having delegates (correct me if I am wrong). This method will allow you to check if there is a window already open (of any kind). The original response works very well, but you can also do it the following way:
Create the interface
public interface IWindowTracker
{
void WindowIsOpened();
void WindowIsClosed();
}
Implement the interface on the parent (from where you are opening):
public partial class MainWindow : Window, IWindowTracker
In your constructor, accept an object that is of the IwindowTracker interface. Save the instance for future use
IWindowTracker windowTracker;
public ProjectManager(IWindowTracker parentWindowTracker)
{
windowTracker = parentWindowTracker;
InitializeComponent();
}
Setup the calls to the window tracker object
protected override void OnActivated(EventArgs e)
{
windowTracker.WindowIsOpened();
base.OnActivated(e);
}
protected override void OnClosed(EventArgs e)
{
windowTracker.WindowIsClosed();
base.OnClosed(e);
}
and finally implement the IWindowTracker in your parent WPF window
bool windowIsOpen = false;
public void WindowIsOpened()
{
windowIsOpen = true;
}
public void WindowIsClosed()
{
windowIsOpen = false;
}
This will allow you to keep track of if the window is still open and if it is, there is no need to open a new instance of it:
if (!windowIsOpen)
{
remoteProjectManager = new ProjectManager(this);
remoteProjectManager.Show();
}
remoteProjectManager.Focus();
Calling show() on a closed window seems to throw an exception, so my guess is that there is some other way or that if you have closed the window, the window is technically "destroyed"
The nice thing to this is that I can detect if the window is still open and focus on it (so that it comes to the front again).
NOTE: There is a draw back to this, in that in this setup it limits you to opening only one window at a time (assuming that all your windows are implemented like this). In my case, I only ever want to have one window open besides the main window.
You might also want to check if your window is null or not, considering that it probably isn't the only window you will have to open.
edit: oops, my answer is specific to Windows Forms. i just now saw the WPF mention. i'm not sure what the specific code would be for WPF, but i would imagine that it's not all that different conceptually. I think in WPF the property is called IsVisible instead of Visible
You could hold on to the instance of your window (or make it a Singleton) and then when you need to determine if it is visible or not, check it's Visible property.
for example:
if(myWindow.Visible){
myWindow.Hide();
}else{
myWindow.Show();
}
This article it the best I found for passing data between WPF pages. The author used KISS approach to provide a simple solution.

Resources