WPF Layout Windows Form Elements Inside ScrollViewer

when placing the ScrollViewer inside the window (without saving all window sizes) inside the ScrollViewer there is (with other materials) WinFormsHost and a control inside (say, DateTimePicker). when scrolling, the internal control of winforms remains visible when there is no more reason (it is outside the scroll area), so it โ€œfloatsโ€ over what's outside of the ScrollViewer

any solutions for this?

+4
source share
3 answers

According to this msdn link

WindowsFormsHost elements are always drawn on top of other WPF elements, and they are not affected by z-order

I do not think this is a simple solution. You might want to think about window shape management handling scrolling, rather than using WPF ScrollViewer.

+6
source

Yes, there is a solution. Use the following custom WindowsFormsHost class.

class WindowsFormsHostEx : WindowsFormsHost { private PresentationSource _presentationSource; public WindowsFormsHostEx() { PresentationSource.AddSourceChangedHandler(this, SourceChangedEventHandler); } protected override void OnWindowPositionChanged(Rect rcBoundingBox) { base.OnWindowPositionChanged(rcBoundingBox); ParentScrollViewer.ScrollChanged += ParentScrollViewer_ScrollChanged; ParentScrollViewer.SizeChanged += ParentScrollViewer_SizeChanged; ParentScrollViewer.Loaded += ParentScrollViewer_Loaded; if (Scrolling || Resizing) { if (ParentScrollViewer == null) return; GeneralTransform tr = RootVisual.TransformToDescendant(ParentScrollViewer); var scrollRect = new Rect(new Size(ParentScrollViewer.ViewportWidth, ParentScrollViewer.ViewportHeight)); var intersect = Rect.Intersect(scrollRect, tr.TransformBounds(rcBoundingBox)); if (!intersect.IsEmpty) { tr = ParentScrollViewer.TransformToDescendant(this); intersect = tr.TransformBounds(intersect); } else intersect = new Rect(); int x1 = (int)Math.Round(intersect.Left); int y1 = (int)Math.Round(intersect.Top); int x2 = (int)Math.Round(intersect.Right); int y2 = (int)Math.Round(intersect.Bottom); SetRegion(x1, y1, x2, y2); this.Scrolling = false; this.Resizing = false; } } private void ParentScrollViewer_Loaded(object sender, RoutedEventArgs e) { this.Resizing = true; } private void ParentScrollViewer_SizeChanged(object sender, SizeChangedEventArgs e) { this.Resizing = true; } private void ParentScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e) { if (e.VerticalChange != 0 || e.HorizontalChange != 0 || e.ExtentHeightChange != 0 || e.ExtentWidthChange != 0) Scrolling = true; } protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing) PresentationSource.RemoveSourceChangedHandler(this, SourceChangedEventHandler); } private void SourceChangedEventHandler(Object sender, SourceChangedEventArgs e) { ParentScrollViewer = FindParentScrollViewer(); } private ScrollViewer FindParentScrollViewer() { DependencyObject vParent = this; ScrollViewer parentScroll = null; while (vParent != null) { parentScroll = vParent as ScrollViewer; if (parentScroll != null) break; vParent = LogicalTreeHelper.GetParent(vParent); } return parentScroll; } private void SetRegion(int x1, int y1, int x2, int y2) { SetWindowRgn(Handle, CreateRectRgn(x1, y1, x2, y2), true); } private Visual RootVisual { get { _presentationSource = PresentationSource.FromVisual(this); return _presentationSource.RootVisual; } } private ScrollViewer ParentScrollViewer { get; set; } private bool Scrolling { get; set; } private bool Resizing { get; set; } [DllImport("User32.dll", SetLastError = true)] static extern int SetWindowRgn(IntPtr hWnd, IntPtr hRgn, bool bRedraw); [DllImport("gdi32.dll")] static extern IntPtr CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); } 
+3
source

Just add the ScrollViewer control property:

 VerticalScrollBarVisibility="Auto" 

and set the height to maximum height. It's all.

0
source

Source: https://habr.com/ru/post/1277081/


All Articles