在ScrollViewer中承载windows窗体元素的WPF

在ScrollViewer中承载windows窗体元素的WPF,wpf,Wpf,将ScrollViewer放入窗口时(不保持所有窗口的大小) 在ScrollViewer中有一个WinFormsHost和一个控件(比如DateTimePicker)。滚动时,内部winforms控件在不再存在原因时保持可见(它位于滚动区域之外),因此它“浮动”在ScrollViewer之外 有什么解决办法吗?根据 WindowsFormsHost元素始终是 在其他WPF元素之上绘制, 它们不受z阶的影响 我认为没有一个简单的解决办法。您可能需要考虑Windows窗体控件处理滚动本身,而不是使用

将ScrollViewer放入窗口时(不保持所有窗口的大小) 在ScrollViewer中有一个WinFormsHost和一个控件(比如DateTimePicker)。滚动时,内部winforms控件在不再存在原因时保持可见(它位于滚动区域之外),因此它“浮动”在ScrollViewer之外

有什么解决办法吗?

根据

WindowsFormsHost元素始终是 在其他WPF元素之上绘制, 它们不受z阶的影响


我认为没有一个简单的解决办法。您可能需要考虑Windows窗体控件处理滚动本身,而不是使用WPF的ScRelVistor。< /P> < P>只需添加ScLoVIEVIEW控件属性:

VerticalScrollBarVisibility="Auto"

并将高度设置为您的最大高度。就这些。

是的,有一个解决方案。使用以下自定义WindowsFormsHost类

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);
    }

有趣的解决方案,可以说它极大地改进了我特定用例中的UI,因为windowsformshosts不再漂浮在scrollviewer容器的下方或上方。。。一些问题:重塑主机需要一些时间,因此在滚动scrollviewer时windowsformshost将“闪烁”,而当存在多个windowsformshost时,情况更糟,因为快速滚动时主机控制区域中会出现工件。请注意,如果windowsformshost在scrollviewer“外部”加载,它可以“浮动”,直到它至少在scrollviewer“内部”一次。这是一个很好的解决方案,虽然我必须更改FindParentScrollViewer实现,以使用VisualTreeHelper正确查找父ScrollViewer。当ScrollViewer包含WindowsFormsHost时,您是否按照问题中的说明进行了测试?据我所知,这没有帮助;winform控件和wpf scrollviewer可能没有正确地相互通信大小。或者winform控件正在覆盖滚动条的像素。在你发表文章之前已经9年了,我想它在那个时候起作用了。挖掘旧答案和向下投票有什么意义?向下投票不是针对个人的。我不会浪费时间“挖掘旧答案”;我写这篇文章的时候碰巧用到了WPF。不幸的是,没有一个“好”的机制来标记过时的答案;我们只有向下投票。[有助于提醒作者和读者,目前这可能不是可靠的答案。]这是一个有用答案的长期数据库的维护,因为我自己碰巧遇到过这种情况。如果你觉得这是一个比坐在这里被否决更好的解决方案,你总是可以选择删除你的答案;这将取消对它的所有投票。(请注意,您的答案在简单的情况下可以正常工作,但在问题中描述的情况下不起作用:当ScrollViewer包含WindowsFormsHost.AFAIK时,情况一直是这样的-原因在接受的答案中的文档引用中提到。这不是以后的一些更改;您只是不知道y时的限制。)你回答了。因此我的评论。)