【问题标题】:WPF Scrollviewer not adjusting to contentWPF Scrollviewer 不适应内容
【发布时间】:2020-06-16 01:03:11
【问题描述】:

我需要在我的 WPF 应用程序中显示一个图像,用透明画布覆盖它并允许用户在其上绘图。用户必须能够缩放图像(放大和缩小)和“导航”图像,同时使用停靠在窗口底部和右侧的某种滚动条进行放大。为了启用图像缩放,我使用了ZoomBorder control,在第二个答案中进行了描述。这是我的 XAML 代码:

<ScrollViewer x:Name="imageScroll" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"  >
  <local:ZoomBorder x:Name="backgroundZoomBorder" ClipToBounds="True" HorizontalAlignment="Center" VerticalAlignment="Center"  Width="{Binding CurrentImageWidth}" Height="{Binding CurrentImageHeight}"  >
     <Grid x:Name="gridDrawing" MouseLeftButtonDown="background_MouseLeftButtonDown" MouseMove="background_MouseMove" MouseLeftButtonUp="background_MouseLeftButtonUp">                           
       <Image  x:Name="mainImage"  Source="{Binding Path=WriteableBmp}" />
       <Canvas x:Name="canvasDrawing"  Background="Transparent" />
     </Grid>
  </local:ZoomBorder>
</ScrollViewer>

这可行,但是,scollviewer 不会调整内容的大小,如果图像放大到最大,或者缩小到最小,它仍然是一样的。如果图像小于窗口区域,它应该消失,或者在图像缩放时具有更大的范围。我可以无论如何将 ScrollViever 绑定到 Image 的转换大小或其他东西吗?或者有没有更好的控制来代替ScrollViewer? 谢谢

【问题讨论】:

    标签: .net wpf image user-interface zooming


    【解决方案1】:

    ScrollViewer 永远不会与ZoomBorder 控件一起使用,因为它使用的是RenderTransformRenderTransform 会操纵您在通过布局系统后看到的内容。因此,它的大小永远不会改变,因此ScrollViewer 永远不会激活。

    通过将ZoomBorder 修改为使用LayoutTransform,您可以获得缩放(滚轮)功能并且ScrollViewer 将激活。但是,要使用鼠标进行平移需要进行更多重大修改。

    以下是一些有效的示例代码:

    使用 LayoutTransform 的 ZoomBorder

    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<ScrollViewer>
        {
            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;
            }
        }
    }
    

    示例用法:

    <ScrollViewer
        HorizontalScrollBarVisibility="Auto"
        VerticalScrollBarVisibility="Auto">
        <i:Interaction.Behaviors>
            <local:ScrollViewerPanBehavior />
        </i:Interaction.Behaviors>
        <local:ZoomBorder
            HorizontalAlignment="Center"
            VerticalAlignment="Center">
            <Grid>
                <Image Source="ThumbsUp.png" />
            </Grid>
        </local:ZoomBorder>
    </ScrollViewer>
    

    这很有趣!

    【讨论】:

    • 好的,我用LayoutTransform试试,非常感谢
    • 再次感谢您,该代码做得非常好。但是它对我不起作用。图像未缩放,滚动查看器仍未调整。唯一似乎可以进行缩放的是在 Image 标记之后放置在 中的 Canvas。我不明白为什么会这样,如果我发现了,我会告诉你的。
    • 好吧,问题出在我的 XAML 中,愚蠢的错误,我将图像的宽度和高度绑定到 ZoomBorder 大小,现在我将其移动到 Grid 标记,它运行良好。你救了我,我感激不尽,上帝保佑你。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-01
    • 1970-01-01
    • 2011-01-20
    • 2012-01-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多