WPF Scrollviewer不会根据内容进行调整

17 浏览
0 Comments

WPF Scrollviewer不会根据内容进行调整

我需要在我的WPF应用程序中显示一张图片,并用透明画布叠加在上面,允许用户在上面绘画。用户必须能够对图片进行缩放(放大和缩小),并在缩放时使用底部和右侧停靠的滚动条在图片中进行“导航”。为了实现图片缩放,我使用了ZoomBorder控件,在第二个答案中有描述。所以这是我的XAML代码:


  
                                
       
       
     
  

这样可以工作,但是滚动框不会根据内容的大小进行调整,无论图片是缩放到最大还是缩放到最小,它仍然保持不变。如果图片小于窗口区域,则应该隐藏它,或者在图片缩放时具有更大的范围。我可以通过绑定ScrollViever到图片的变换大小或其他方式来实现吗?或者是否有其他更好的控件可以替代ScrollViewer?

谢谢。

0
0 Comments

问题出现的原因是因为使用了RenderTransform,而RenderTransform是在布局系统之后才进行操作的,因此其大小永远不会改变,因此ScrollViewer永远不会启动。

解决方法是修改ZoomBorder,使用LayoutTransform来实现缩放功能。然而,要使鼠标的平移功能正常工作,需要进行更大的修改。

下面是一些示例代码,可以使其正常工作:

ZoomBorder using LayoutTransform

using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace SO
{
    public class ZoomBorder : Border
    {
        private FrameworkElement child;
        private ScaleTransform GetScaleTransform(FrameworkElement element)
        {
            return (ScaleTransform)((TransformGroup)element.LayoutTransform)
              .Children.First(tr => tr is ScaleTransform);
        }
        public override UIElement Child
        {
            get => base.Child;
            set
            {
                if (value != null && value != Child)
                    Initialize(value);
                base.Child = value;
            }
        }
        public void Initialize(UIElement element)
        {
            child = (FrameworkElement)element;
            if (child == null) return;
            var group = new TransformGroup();
            var st = new ScaleTransform();
            group.Children.Add(st);
            child.LayoutTransform = group;
            child.RenderTransformOrigin = new Point(0.0, 0.0);
            MouseWheel += child_MouseWheel;
            PreviewMouseRightButtonDown += child_PreviewMouseRightButtonDown;
        }
        public void Reset()
        {
            if (child == null) return;
            // reset zoom
            var st = GetScaleTransform(child);
            st.ScaleX = 1.0;
            st.ScaleY = 1.0;
        }
        #region Child Events
        private void child_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            if (child != null)
            {
                var st = GetScaleTransform(child);
                var zoom = e.Delta > 0 ? .2 : -.2;
                if (!(e.Delta > 0) && (st.ScaleX < .4 || st.ScaleY < .4)) return;
                st.ScaleX += zoom;
                st.ScaleY += zoom;
            }
        }
        void child_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            Reset();
        }
        #endregion
    }
}

ScrollViewerPanBehavior

通过鼠标拖动来处理平移的行为。

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;
namespace SO
{
    public class ScrollViewerPanBehavior : Behavior
    {
        private UIElement content;
        private Point scrollMousePoint;
        private double scrollHorizontalOffset;
        private double scrollVerticalOffset;
        public ScrollViewerPanBehavior()
        {
        }
        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.Loaded += OnLoaded;
        }
        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            content = (UIElement)AssociatedObject.Content;
            content.MouseLeftButtonDown += OnMouseLeftButtonDown;
            content.MouseMove += OnMouseMove;
            content.MouseLeftButtonUp += OnMouseLeftButtonUp;
        }
        private void OnMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            content.CaptureMouse();
            AssociatedObject.Cursor = Cursors.Hand;
            scrollMousePoint = e.GetPosition(AssociatedObject);
            scrollHorizontalOffset = AssociatedObject.HorizontalOffset;
            scrollVerticalOffset = AssociatedObject.VerticalOffset;
        }
        private void OnMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (content.IsMouseCaptured)
            {
                var newVerticalOffset = scrollVerticalOffset + (scrollMousePoint.Y - e.GetPosition(AssociatedObject).Y);
                var newHorizontalOffset = scrollHorizontalOffset + (scrollMousePoint.X - e.GetPosition(AssociatedObject).X);
                AssociatedObject.ScrollToVerticalOffset(newVerticalOffset);
                AssociatedObject.ScrollToHorizontalOffset(newHorizontalOffset);
            }
        }
        private void OnMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            content.ReleaseMouseCapture();
            AssociatedObject.Cursor = Cursors.Arrow;
        }
    }
}

示例用法:


    
        
    
    
        
            
        
    

这真的很有趣!好的,我会尝试使用LayoutTransform,非常感谢你。

再次感谢你,你的代码非常棒。然而,对我来说并没有起作用。图像不会缩放,滚动视图仍然不会调整。唯一似乎能够缩放的是在Image标记之后放置的Grid标记中的Canvas。我无法理解为什么会发生这种情况,如果我找到原因,我会告诉你。

好的,问题出在我的XAML中,愚蠢的错误,我将图像的宽度和高度绑定到了ZoomBorder的大小上,现在我将其移动到了Grid标记中,现在它完美地工作了。你救了我,我无法感谢你,上帝保佑你。

0