WPF Listbox with touch inertia pulls down entire window - c#

I have a full screen WPF application built for a touch monitor, and I have some Listboxs on the main screen.
When I flick the 'Listbox' it scrolls fine, but when it gets to the end of the list, the entire application gets pulled down from the top of the screen, can I stop this behavior somehow?
Has anyone else seen this?

Yes, that default behaviour of the ListBox (or rather, the ScrollViewer inside the default ListBox template) is weird - when I first came across it, I thought it must be a practical joke. In fact, it's really hard to find any documentation about it - but it is briefly mentioned here:
The ManipulationBoundaryFeedback event enables applications or components to provide visual feedback when an object hits a boundary. For example, the Window class handles the ManipulationBoundaryFeedback event to cause the window to slightly move when its edge is encountered.
So, a way around it is to handle ManipulationBoundaryFeedback on the ListBox, and set Handled to true:
<ListBox ManipulationBoundaryFeedback="OnManipulationBoundaryFeedback">
// ...
</ListBox>
Code-behind:
private void OnManipulationBoundaryFeedback(object sender, ManipulationBoundaryFeedbackEventArgs e)
{
e.Handled = true;
}

Related

Struggling with WPF internal methods

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?

TouchDown event is delayed

My application uses the UiElement.TouchDown event in various places, one of them is to let the user stop a spinning wheel. In this situation, one can easily notice a short delay of about 1/3s between the actual touching of the screen and the TouchDown event.
I have set Stylus.IsPressAndHoldEnabled to false.
In order to troubleshoot this problem, I've written a test tool that reports WPF events and native window messages, and I noticed that as soon as I touched the screen, messages with id 0x02CC, 0x011B and 0x011A are generated, about 100 to 300 ms before the TouchDown event. This leads me to believe that the drivers report the touch quickly, and the delay is introduced somewhere later in the WPF translations.
Is there a way to make the touch interaction more responsive? Please ask for any information you need!
Unless Flicks are needed set both in XAML or by manually setting in code behind: (I assume you meant to say IsPressAndHoldEnabled not IsTouchAndHoldEnabled)
Stylus.IsPressAndHoldEnabled="False" Stylus.IsFlicksEnabled="False"
Furthermore consider handling the TouchDown Event and also capturing it to the relevant UIElement (don't forget to release it in TouchUp).
uielement.CaptureTouch(e.TouchDevice);
e.Handled = true;

How to scroll a ListBox programmatically the same way the MouseWheelEvent does?

Ok, I have the following problem:
I would like to scroll an overflowing ListBox up and down.
I would like to do it programatically in a custom control inheriting from ListBox. I've seen and tested things such as scrollIntoView. However I would like to have a scrolling similar to what you can have when using the mouse's wheel.
I don't want to have the mouse involved at all (I'm developing for the Kinect, and since there are 2 cursors, I don't want to use the Mouse event args)
a google search didn't turn up much: I've read plenty of thread on how to scroll in code behind using scrollIntoView, or putting a scrollbar and such.
I think this will involve two steps:
Find the scrollViewer control inside listBox template
Perform the actual scrolling in that scrollViewer
For the first step implementation please take a look here. Here is the code snippet extracted from there:
this.Loaded += MainWindow_Loaded;
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
var scrollViewer = listbox.Template.FindName("Scroller", listbox);
}
And for the second step you should use one of the methods from here, LineDown or PageDown probably.
P.S.: I haven't tested this approach at all since I do not have VS installed so feel free to add the needed code here.

What is the last event to fire when loading a new WPF/C# window?

I am trying to load a preferences window for my application and I would like the apply button to initially be disabled, then when a preference is updated, the apply button gets enabled again. I have some controls data bound to a preferences object and what happens is that after the window loads, the combobox events get triggered. Is there any event that is guaranteed to happen dead last after everything is stable?
Here is what my code looks like (the apply button is always enabled after the window loads):
private void Window_Loaded(object sender, RoutedEventArgs e)
{
_preferencesData = new PreferencesDataContext();
LayoutRoot.DataContext = _preferencesData;
ButtonApply.IsEnabled = false;
}
private void ComboBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
ButtonApply.IsEnabled = true;
}
Is it also interesting to note that this only happens with textboxes and comboboxes, not checkboxes or radiobuttons.
Best solution for simple need
Joseph's answer is the best solution by far for your simple need: Just use data binding and let the data model handle it.
Answer to question as posed
There are more complex scenarios when you really do need control after absolutely everything has finished loading and all events have fired. There is no single event that occurs "dead last", but it is easy to effectively roll your own using the Dispatcher queue.
This is how to do it:
Dispatcher.BeginInvoke(DispatcherPriority.ContextIdle, new Action(() =>
{
var x = ComputeSomething(1, 2, 3);
DoSomething(x, "Test");
}));
Everything inside the { } will be executed when WPF finishes everything at a higher priority than ContextIdle, which includes all event handlers, loaded events, input events, rendering, etc.
Sequence of events when a Window is created and shown
As requested, here is the sequence of major events in WPF when a window is created and shown:
Constructors and getters/setters are called as objects are created, including PropertyChangedCallback, ValidationCallback, etc on the objects being updated and any objects that inherit from them
As each element gets added to a visual or logical tree its Intialized event is fired, which causes Styles and Triggers to be found applied in addition to any element-specific initialization you may define [note: Initialized event not fired for leaves in a logical tree if there is no PresentationSource (eg Window) at its root]
The window and all non-collapsed Visuals on it are Measured, which causes an ApplyTemplate at each Control, which causes additional object tree construction including more constructors and getters/setters
The window and all non-collapsed Visuals on it are Arranged
The window and its descendants (both logical and visual) receive a Loaded event
Any data bindings that failed when they were first set are retried
The window and its descendants are given an opportunity to render their content visually
Steps 1-2 are done when the Window is created, whether or not it is shown. The other steps generally don't happen until a Window is shown, but they can happen earlier if triggered manually.
The Window.ContentRendered event fulfilled my requirements.
I just did kind of the same thing behaviorly in a systray WPF app.
However, I didn't do it using event handling. I simply bound the Enabled property of my button to a property in my ViewModel, and had the property updated whenever I needed the behavior.
You can use ManagedSpy to figure this out on your own.
http://msdn.microsoft.com/en-us/magazine/cc163617.aspx
Setting the DataContext will likely fire the SelectionChanged event, and you can't rely on when exactly it's fired. Some logic checking on what exactly is selected would be more reliable:
private void ComboBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
if (myComboBox.SelectedItem == null)
{
buttonApply.IsEnabled = false;
}
else
{
buttonApply.IsEnabled = true;
}
}
The reason it's happening afterwards with your code as-is is because the event gets queued on the thread for the UI, so it's up to Windows if it will execute the next line of code in Load, or to handle the other events on the queue.
Not to throw a whole lot of stuff at you that you may or may not be familiar with, but if this is a relatively new codebase, you may want to consider using the MVVM pattern and use Commands instead of the archaic (emphasis mine) eventing model.
Order of Events in Windows Forms
Control.HandleCreated
Control.BindingContextChanged
Form.Load
Control.VisibleChanged
Form.Activated
Form.Shown

How to disable controls in Windows Media Player in WPF

I was just wondering if there is a way to disable controls such as ctr Left/Right arrows or Alt+left/right arrows in AxWindowsMediaPlayer. I am using it in WindowsFormsHost in my WPF project. I would like to capture these controls and handle them myself. When I use this block, I don't have any way to prevent it by using e.handeld =true or other ways
void MediaPlayer_KeyDownEvent(object sender, AxWMPLib._WMPOCXEvents_KeyDownEvent e)
{
}
Any suggestion how to disable it and continue with my own controls. The important part is it bubbles up somewhere and freezes the GUI if I use such commands, and I don't have any way to capture it to control. It doesn't have any error though.
thanks
It can be blocked in WindowsFormHost level by controlling keydown.
I have one thought to try, but I haven't tested it. Inherit from WindowsFormsHost and override WndProc() method. In this method capture WM_KEYDOWN message, process it, and if it's a key you want to suppress, return 0.
If it doesn't work, you may want to find other way to hook windows procedure.
Hope this helps.
Cheers, Anvaka

Categories

Resources