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!
Related
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
I have a WPF Application that receive FrameworkElement objects from 3rd party API.
I would like to register events on those objects.
Is this possible? This not working:
public void DisplayControl(FrameworkElement control)
{
control.MouseEnter += new MouseEventHandler(Control_MouseEnter);
control.MouseDown += new MouseButtonEventHandler(Control_MouseDownFromElement);
VideoGrid.Children.Add(control);
}
void Control_MouseDownFromElement(object sender, EventArgs e)
{
lblOutput.Content = string.Format("Sender is: " + sender.ToString());
}
void Control_MouseEnter(object sender, EventArgs e)
{
(sender as FrameworkElement).Focus();
}
One possible reason is the control provider is intentionally blocking that event... you can try adding a control(say grid) on the top of the original control with 0.01 opacity means virtually the control we have added is not visible to the user and we can write all the events on the invisible control...
Update
Something like this... create a grid with opacity 0.01 add events to that grid and add the grid to the video grid after adding your control... so in the video grid there will be control and on the top of the control there will be grid which is invisible because of its opacity and your events will work on the grid... make sure to give same height and width to the grid that match with your control height and width....
Grid grd = new Grid();
grd.Opacity = 0.01;
grd.MouseDown += new MouseButtonEventHandler(Grid_MouseDown_1);
VideoGrid.Children.Add(control);
VideoGrid.Children.Add(grd)
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;
}
}
I am using a GridSplitter to resize columns (what else :)). Works fine.
However, I am evolving in a Surface V2 environment and if I use touch simulation the Touch events are not transmitted to my dear GridSplitter.
Any hint on how to make that work?
Just register the event like this:
YourGridSplitter.PreviewDragEnter += new DragEventHandler(YourGridSplitter_PreviewDragEnter);
void YourGridSplitter_PreviewDragEnter(object sender, DragEventArgs e)
{
// nothing here
}
You need to capture the touchdevice.
gs.PreviewTouchDown += (s, e) => { e.TouchDevice.Capture((s as UIElement)); };
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