Scenario: The customers have the ability to set an annotation to the PDF page. This is handled as a richtextbox object. There's a bug, however, that when the user is making an annotation and wants to scroll down manually (drag scrollbar down), that the annotation moves with it.
I want to implement code that detects the scroll event, so that the annotation can be exited and placed properly before the program scrolls down/up.
What was to be a simple procedure, ended up in a not so simple venture, but I'm getting used to that evolution in programming...
We can see the WM_VSCROLL message with spy++, but can't find it with a Console.Writeline in wmdproc, which points to it being handled by an event, but for the life of us, we can't find which event exactly.
We tried overriding our mistery scroll event in both the MainForm as its parent, but no success. Also tried overriding it in the PDFViewCtrl, but it forbids us to override there.
So we're kind of at a loss here. We know the event is handled, we just can't find where.
We use Pdftron and DevExpress, but it's worth noting that we do not use their DE's PDFViewer. Ours is a PDFViewCtrl loaded into a DevExpress Xtraform.
The annotation scrolling is the expected behaviour. Triggering the lost focus event when clicking on the scroll bars is not possible with the PDFViewCtrl class.
Related
UPDATE: So, I have a solution to my immediate problem. I haven't succeeded in making "my own" TreeView class. But, the reason I wanted to do that was because controls based on ButtonBase don't function in a Popup from a TreeView, and with the help of #MarkFeldman, I have found a solution that comes at it from a different angle.
The problem is that the MouseDown and MouseUp events bubble, and that bubbling crosses the logical tree boundary between the Popup and its owner. So, when you click on something hosted inside the Popup, the TreeViewItem and TreeView that ultimately own the Popup get to hear about it. This then triggers code inside the TreeView that checks, "Do I have focus?", and if not, helpfully sets focus back to itself -- but being a separate logical tree, the Popup has its own focus context, and so this effectively steals focus from the Button control while it is in the middle of processing a click. The Button responds to this by ignoring the click.
This erroneous handling in the TreeView only happens when MouseDown and MouseUp events reach it. What if there were a way to prevent it from seeing those events in the first place? Well, if you intercept the PreviewMouseDown and PreviewMouseUp events and mark them Handled, then the framework doesn't generate MouseDown and MouseUp events to begin with.
Looking at the Reference Source, it looks like ButtonBase's click handling is tied up in a couple of protected methods:
https://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/Controls/Primitives/ButtonBase.cs,414
https://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/Controls/Primitives/ButtonBase.cs,478
This means you can call them from your own subclasses! So, instead of making "my own" TreeView where all controls behave properly, instead I can make "my own" CheckBox that works properly in a Popup from a TreeView. Since all of the actual click handling is directly accessible, and the events it normally responds to use the same EventArgs type as the Preview events, and on top of it the default handling takes care of marking the events as Handled, the entire implementation boils down to this:
public class CheckBoxThatWorks : CheckBox
{
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e) => base.OnMouseLeftButtonDown(e);
protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e) => base.OnMouseLeftButtonUp(e);
}
Nice!
ORIGINAL QUESTION:
I need to make a clone of the TreeView WPF class -- a copy of the control that runs out of my own code. (There is a bug in the control and Microsoft doesn't seem to deem it high-enough priority to fix, and it makes it completely impossible to host buttons (including check boxes and radio buttons) within pop-ups shown from TreeViewItems. link)
I am running into serious difficulties with the amount of internal shenanigans Microsoft has undertaken in the implementation of base WPF controls. A couple of issues I've bumped into:
Controls have a property HandlesScrolling that allows them to take over basic scrolling handling from ScrollViewer. But, it's marked internal, making it seemingly impossible for me to have a control of my own that does its own handling of scrolling from keyboard input. I was going to try having my TreeView handle keyboard scrolling in OnPreviewKeyDown instead of OnKeyDown, so that it can prevent KeyDown events from being raised for the keys it intercepts. I haven't gotten far enough to know what caveats there might be about this.
The Visual States system allows you to declare what styles should be applied when different states are entered, but actually entering states seems to be tied up in the virtual method ChangeVisualState on the Control type. All controls that want to switch between visual states can override this method and inspect their state to determine which Visual State should be shown. Oh wait. They can't because the method is internal! Apparently only Microsoft gets to create controls that set their own visual states??
Are there any strategies I can use to work around these limitations, or am I just completely out of luck?
I have a form which I would like to block during execution of an async event. I would like to achieve an effect similar to when a dialog window is displayed, without displaying or creating one.
I don't want to manually disable controls on the form, as some controls may be added in the future (not necessarily by me). I would like to avoid disabling the entire form / user control for aesthetic reasons.
Is there a standard/elegant way of achieving this, or am I going in a wrong direction?
You can block WinForm window by setting it's Enabled property to false, but it will prevent user from any action with that window (like moving, resizing or hiding) and it may be very annoying. Consider showing some load indicator instead.
I would not recommend to disable controls without making them look disabled because it could confuse user.
Edit: As #AvoNappo pointed out window behavior differs depend on where to set Enable property to false:
if you set it in the constructor user still will be able to move/minimize/close window;
if you call it after constructor window control buttons and windows movement also will be blocked.
I've been playing around with events in WPF and have so far I've got good mileage out of 'Source' and 'OriginalSource' properties of the event args as well as using the sending control and FocusManager. Here's the thing, when a chain of events starts firing, is there any way to know what control will be ending up with focus at the end barring any intervening logic throughout the chain of events?
I'm afraid that the only reliable way of doing this is actually letting focus change and then handling it in some PreviewGotKeyboardFocus handler at top view level.
You can then know which control was going to get the focus, and cancel the change with e.Handled = true.
PD. There's a function in all UIElements called PredictFocus, but it only works with positional traverse changes, not with tab-based changes (or custom focusing).
As far as I know, these are the only keys that react when a button has focus.
Pressing Enter instantly 'clicks' the button, even if you keep it the key down. (So the 'click' happens on KeyDown).
Pressing Space acts more like a normal mouse click; holding it down doesn't activate the Click event, but it does once you release it. (So the 'click' happens on KeyUp or KeyPressed.)
Why the difference? I'd like a good article on the subject or simply a logical explanation as to why those two keys have different behavior. Surely there's an explanation out there!
I can't find any articles explaining this and it's a really good question. I personally think that it's for functionality purposes
Enter Key the classic AcceptButton acts like a FullClick (Click/ClickReleased) that's why if you hold it you will have the effect of clicking multiple times.
Space however is a SingleClick (No click release until you release the key) so it can accomplish task where only a Click is required without a ClickRelease and actions where only the selection of a control is required to activate it. Like the CheckBox or RadioButtons which can't be activate with the Enter but can be activated with the Space like if you click on it.
In conclusion, the Space would be the official MouseClick since it has the same effects of a MouseClick uppon pressing or releasing. Enter would be sort of a shortcut for a One click full click. All, of course, in the idea of giving more possibilities to the keyboard itself.
You're seeing two different behaviors, which aren't associated except that they both deal with keyboard events on a winform.
Enter is special because it's the keypress to activate the acceptButton of a form. In fact, you missed another key that can affect buttons: Esc is the cancelButton, and will throw events as well.
As PhaDaPhunk explained, Space is a MouseClick for any component that accepts a MouseClick, but I haven't found a detailed explanation for it. I'd assume it's the default behavior of all controls. The Microsoft guide to accessibility seems to imply that is so in their section on keyboard-based navigation
Incidentally, this Microsoft support knowledge base entry seems to show that the spacebar implementation went from Button.Click to Button.MouseClick. Perhaps that's the reason for it's different behavior.
This functionality seems to have been removed in Big Sur. I came here looking for how I could get it back. It can be very efficient to click enter to proceed or spacebar usually to cancel, to pick the two primary options on most dialog buttons.
I'm adding a syndication (RSS) feed into a Bing maps application where the data is downloaded and populated on a mouse over event. The download is super fast but of course it has to be downloaded asynchronously meaning the user won't see the tooltip populated until the next time they mouse over that tool tip. I know that, for security reasons, I shouldn't necessarily be able to emulate a mouse-over event, but I know there are other things like this where there is a workaround (for example, if a user is logging in and enters their username and password - there's a workaround so that they can press 'ENTER' without the Login/Submit button having focus).
So first I'm wondering if there's a workaround and, if not...is there an easier way to do this than emulating a synchronous download via coroutines (worth noting: MVVM can not be used here due to the way the nature of the model - Also, each pin has its own tool tip rather than a single custom tool tip where the position would be determined on mouse over via MapLayer.SetPosition)
Thanks!
figured it out - just attach a boolean property on the mouse enter event and to make sure the mouse is still over the element providing the tool tip - on mouse enter set the mouse leave bool to false and the tool tip's IsOpen property to false. When the download has completed - bind your DataContext to the object with relevant data (or however you want to go about this) then, if mouse leave bool is still equal to false, set the IsOpen property = true