Touch Scrolling ScrollViewer in WPF App with RealTimeStylus Disabled - wpf

We are working on a WPF 4.5 application that will be run on Windows 8 computers with touchscreen monitors.
We have disabled support for the RealTimeStylus following the directions on the MSDN, since we have some views that need multitouch support through WM_TOUCH.
The problem is that disabling the RealTimeStylus support seems to also disable the user's ability to scroll a ScrollViewer using touch - normally the user can pan around ScrollViewers with their fingers, but if RealTimeStylus support is disabled, it does not seem possible to do this. The ScrollViewer's PanningMode is set to "Both".
Is it possible to combine these things in a WPF application, or are they mutually exclusive?

Another option is to add arrow buttons around the content. We've used this to great effect on a touch screen kiosk. It's a bit more work, but could be made into a custom control. The only code I have supports vertical scrolling.
It should be easy enough to add horizontal scrolling as well. In the code below, there are two buttons, called Less and More above and below the scroller.
double Epsilon = .001;
private void Scroller_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
if ( Scroller.ScrollableHeight > 0 ) {
Less.Visibility = Math.Abs(Scroller.VerticalOffset - 0) > Epsilon ? Visibility.Visible : Visibility.Hidden;
More.Visibility = Scroller.VerticalOffset + Scroller.ViewportHeight < Scroller.ExtentHeight ? Visibility.Visible : Visibility.Hidden;
} else {
Less.Visibility = More.Visibility = Visibility.Hidden;
}
if (Scroller.ExtentHeight / Scroller.ViewportHeight > 2)
{
SearchPanel.Visibility = Visibility.Visible;
}
}
private void Less_Click(object sender, RoutedEventArgs e)
{
Sounds.Click();
Scroller.PageUp();
}
private void More_Click(object sender, RoutedEventArgs e)
{
Sounds.Click();
Scroller.PageDown();
}

Can you try SurfaceScrollViewer instead of normal ScrollViewer.
SurfaceScrollViewer

Related

Which control to show readonly colorful text in WPF?

I want an element or a control to show readyonly, colorful, selectable, scrollable text which is a kind of log in my application. I don't know whether it is fixed document or flow document.
The RichText may be the seeming choice, but it originally supports editing. I believe even I set readonly=true, the build-in editing support takes some resources. I want to find a lighter-weight one.
Perhaps the FlowDocumentScrollViewer? It is readonly and do not show tool bar by default. Even I turn IsToolBarVisible on, the tool bar is just a small control.
The Block came into my mind. Although it may be the lightest control, I cannot select the text in it without other effort.
Maybe other choices exist? What's your opinions?
I made an experiment to help me choose my preferable control among FlowDocumentScrollViewer, RichTextBox, and TextBlock. I find FlowDocumentScrollViewer is the best.
In each window I have two controls of same type: FlowDocumentScrollViewer, RichTextBox, or TextBlock. And I made three such windows, as the MainWindow has three buttons.
private void prepareButton_Click(object sender, RoutedEventArgs e)
{
document1 = HelperClass.GetDocument();
document2 = HelperClass.GetDocument();
}
private void loadButton_Click_1(object sender, RoutedEventArgs e)
{
Stopwatch watch = new Stopwatch();
watch.Start();
viewer1.Document = document1;
viewer2.Document = document2;
this.Dispatcher.BeginInvoke(DispatcherPriority.Loaded,
new Action(() =>
{
watch.Stop();
MessageBox.Show("Took " + watch.ElapsedMilliseconds + " ms",Title);
}));
}
Where viewer1 and viewer2 can be FlowDocumentScrollViewer or RichTextBox.
For TextBlock, I use
private void prepareButton_Click(object sender, RoutedEventArgs e)
{
inlines1 = HelperClass.GetInlines();
inlines2 = HelperClass.GetInlines();
}
private void loadButton_Click_1(object sender, RoutedEventArgs e)
{
Stopwatch watch = new Stopwatch();
watch.Start();
viewer1.Inlines.AddRange(inlines1);
viewer2.Inlines.AddRange(inlines2);
this.Dispatcher.BeginInvoke(DispatcherPriority.Loaded,
new Action(() =>
{
watch.Stop();
MessageBox.Show("Took " + watch.ElapsedMilliseconds + " ms");
}));
}
The test indicates FlowDocumentScrollViewer has best performance among the three:
FlowDocumentScrollViewer RichTextBox TextBlock
Working set 65400 67252 82124
Loading Time 1045 1414 45119
I'm not sure what type of resources you think are being taken up by "editing" functionality. The ability to select text goes hand in hand with ability to edit text.
If you want one, you'll have to put up with the other. Luckilly, setting IsReadOnly to "True" will satisfy your functional requirements.
If your application machine is capable of running the .NET Framework with WPF, I wouldn't worry about tiny amounts of resources which may (or may not) be consumed by the ability to edit simple text.

Synchronise 2 scrollviewers silverlight

I want to synchronize 2 scrollviewers. Please let me know how to get scroll event of both scrollviewers and then synchronize them both?
First get the 2 scrollbars of the scrollviewers you want to sync.
In this case, scrollviewer1 and scrollviewer2
Then we get event handlers of both the scrollbars, in this case vertical. Then we can easily sync them through the events. The ScrollToVerticalOffset will scroll as per the other one does.
ScrollBar vertical1 = ((FrameworkElement)VisualTreeHelper.GetChild(scrollviewer1, 0)).FindName("VerticalScrollBar") as ScrollBar;
vertical1.ValueChanged += new RoutedPropertyChangedEventHandler<double>(vertical1_ValueChanged);
ScrollBar vertical2 = ((FrameworkElement)VisualTreeHelper.GetChild(scrollviewer2, 0)).FindName("VerticalScrollBar") as ScrollBar;
vertical2.ValueChanged += new RoutedPropertyChangedEventHandler<double>(vertical2_ValueChanged);
void vertical1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
scrollviewer2.ScrollToVerticalOffset(e.NewValue);
}
void vertical2_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
scrollviewer1.ScrollToVerticalOffset(e.NewValue);
}
Hope this helps!

Avalon Dock Auto Hide problems on load

I am having a problem with Avalon Docking where my second panel that's docked at the bottom and set to AutoHide.
When UI runs the pane loads as Docked/Visible by default. I would like to have it hidden/minimized.
<ad:DockingManager>
<ad:ResizingPanel Orientation="Vertical">
<ad:DocumentPane>
<ad:DocumentContent>
<... data grid that fills the view>
</ad:DocumentContent>
<ad:DocumentPane>
<ad:DockablePane>
<ad:DockableContent Title="output" DockableStyle="AutoHide" IsCloseable="False">
<...some control>
I have tried various "hacks" suggested on Avalon forums, where OnLoad, you can
outputDockablePane.ToggleAutoHide();
and that works, meaning, when UI is loaded the pane is hidden. However, once you toggle auto hide in .cs code, clicking on the dock header at runtime to make the pane visible/float stops working. So you have to hook up DockingMananger.OnMouseUp() and parse through a couple of boolean states and manually call ToggleAutoHide() - I guess only on the time. Seems like a hack to me.
Here's what I am doing for now, till I find a proper and clean solution:
private void OnDockManagerLoaded(object sender, RoutedEventArgs e)
{
if(_firstTimeLoad && !_isDataGridLoaded)
{
outputDockablePane.ToggleAutoHide();
_forcedToAutoHide = true;
}
}
private void OnDockingManagerMouseUp(object sender, MouseButtonEventArgs e)
{
if (_forcedToAutoHide)
{
_forcedToAutoHide = false;
outputDockableContent.Activate();
outputDockablePane.ToggleAutoHide();
}
}
Is there a setting/property that I am totally missing, or/and a better way?
4 Years still Avalon Docking has the same issue .While I haven't found a proper solution yet , I have tried to refine you workaround logic.
private void OnDockingManagerMouseUp(object sender, MouseButtonEventArgs e)
{
if (outputDockableContent.IsAutoHidden)
{
outputDockableContent.IsActive = false;
}
}

Create my own Slider for multitouch application

The Slider control in WPF doesn't work properly for what I'm looking for.
I need to slide 2 different controls (Slider) at the same time (with one finger each).
When I touch the first Slider, it gets all the focus and I cannot touch anything else with my second touch device.
So I need to create my own Slider (MySlider) that inherit from Slider.
I've made 4 methods:
protected override void OnTouchDown(TouchEventArgs e)
protected override void OnTouchUp(TouchEventArgs e)
protected override void OnTouchLeave(TouchEventArgs e)
protected override void OnTouchMove(TouchEventArgs e)
But is there a way to move the Slider exactly like with the mouse? Or I need to calcule each time my touch device moved something like:
protected override void OnTouchMove(TouchEventArgs e)
{
base.OnTouchMove(e);
if (this.Value <= this.Maximum && this.Value >= this.Minimum)
{
Point newPoint = e.GetTouchPoint(this).Position;
this.Value += (this.lastPoint.Y - newPoint.Y);
lastPoint = newPoint;
}
e.Handled = true;
}
And in this case the movement doesn't move at the same speed as the finger...
You might want to check out the Surface 2.0 SDK as it contains a class called SurfaceSlider, which I believe will allow for two or more sliders to be updated simultaneously. This SDK can be used to target applications built for Windows 7.
I'm not familiar with multi-touch events in WPF so will not be able to help you with that. However, for moving the mouse to the same location as your touching then you can look at this answer here.
Your problem that you're assuming that the width of the control is equivalent to the maximum value. You need to take out the factor the actual width relative to the difference between the max and min values.
This can only be done via events since no routed event or DPs for mouse position.

WPF Mousedown => No MouseLeave Event

I'm building a Windows Presentation Foundation control with Microsoft Blend.
When I leave my control by pressing the left-mouse-button, the MouseLeave-Event is not raised. Why not?
This is intended behaviour: When you are doing mousedown on a control and leaving the control, the control STILL retains its "capture" on the mouse, meaning the control won't fire the MouseLeave-Event. The Mouse-Leave Event instead will be fired, once the Mousebutton is released outside of the control.
To avoid this, you can simple tell your control NOT to capture the mouse at all:
private void ControlMouseDown(System.Object sender, System.Windows.Forms.MouseEventArgs e)
{
Control control = (Control) sender;
control.Capture = false; //release capture.
}
Now the MouseLeave Event will be fired even when moving out while a button is pressed.
If you need the Capture INSIDE the Control, you need to put in more effort:
Start tracking the mouseposition manually, when the mousekey is pressed
Compare the position with the Top, Left and Size Attributes of the control in question.
Decide whether you need to stop the control capturing your mouse or not.
public partial class Form1 : Form
{
private Point point;
private Boolean myCapture = false;
public Form1()
{
InitializeComponent();
}
private void button1_MouseDown(object sender, MouseEventArgs e)
{
myCapture = true;
}
private void button1_MouseMove(object sender, MouseEventArgs e)
{
if (myCapture)
{
point = Cursor.Position;
if (!(point.X > button1.Left && point.X < button1.Left + button1.Size.Width && point.Y > button1.Top && point.Y < button1.Top + button1.Size.Height))
{
button1.Capture = false; //this will release the capture and trigger the MouseLeave event immediately.
myCapture = false;
}
}
}
private void button1_MouseLeave(object sender, EventArgs e)
{
MessageBox.Show("Mouse leaving");
}
}
of course you need to stop the own tracking ( myCapture=false;) on MouseUp. Forgot that one :)
When I don't get mouse events I expect I typically use Snoop to help me understand what is happening.
Here are a couple of links:
1- Snoop (a WPF utility)
2- CodePlex project for Snoop
And for completeness and historical reasons (not the bounty - it doesn't make sense having two duplicate questions - you should probably move it into one if not too late)...
I made a thorough solution using global mouse hook here (approach 2)
WPF: mouse leave event doesn't trigger with mouse down
And simplified its use - you can use it by binding to commands in your view-model - e.g.
my:Hooks.EnterCommand="{Binding EnterCommand}"
my:Hooks.LeaveCommand="{Binding LeaveCommand}"
my:Hooks.MouseMoveCommand="{Binding MoveCommand}"
...more details in there
Old question but I came across the same problem with a Button (MouseLeave does not fire while MouseDown because MouseDown Captures the Mouse...)
This is how I solved it anyway:
element.GotMouseCapture += element_MouseCaptured;
static void element_MouseCaptured(object sender, MouseEventArgs e)
{
FrameworkElement element = (FrameworkElement)sender;
element.ReleaseMouseCapture();
}
Hope that helps someone looking for a quick fix :P

Resources