示例:WPF应用Behaviors封装的Zoom效果

一、目的:封装Zoom效果到Behavior中,方便实现鼠标滚轮定点放大缩小,鼠标拖动等效果

 

二、实现

1、鼠标滚轮定点放大缩小

2、鼠标拖动平移

3、恢复初始位置

4、设置缩放是否应用在整个容器中

5、设置居中对齐还是居左对齐

6、通过行为直接加载

三、示例

 

四、实现过程

1、如下定义Behavior

    /// <summary> Zoom带有鼠标移动平移和滚轮定点放大效果 </summary>
    public class ZoomWithWheelAndMoveBehavior : Behavior<FrameworkElement>
    {
        //  Message:外部需要嵌套Grid
        Grid parent;

        //  Message:Zoom控件
        ZoomableCanvas zoomable;

        /// <summary> 是否在父容器中也使用平移和缩放 </summary>
        public bool UseInParent
        {
            get { return (bool)GetValue(UseInParentProperty); }
            set { SetValue(UseInParentProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty UseInParentProperty =
            DependencyProperty.Register("UseInParent", typeof(bool), typeof(ZoomWithWheelAndMoveBehavior), new PropertyMetadata(default(bool), (d, e) =>
            {
                ZoomWithWheelAndMoveBehavior control = d as ZoomWithWheelAndMoveBehavior;

                if (control == null) return;

                control.RefreshEvent();

            }));


        public bool IsCenterInZoom
        {
            get { return (bool)GetValue(IsCenterInZoomProperty); }
            set { SetValue(IsCenterInZoomProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsCenterInZoomProperty =
            DependencyProperty.Register("IsCenterInZoom", typeof(bool), typeof(ZoomWithWheelAndMoveBehavior), new PropertyMetadata(default(bool), (d, e) =>
            {
                ZoomWithWheelAndMoveBehavior control = d as ZoomWithWheelAndMoveBehavior;

                if (control == null) return;

                control.RefreshLocation();

            }));


        public bool IsReturn
        {
            get { return (bool)GetValue(IsReturnProperty); }
            set { SetValue(IsReturnProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsReturnProperty =
            DependencyProperty.Register("IsReturn", typeof(bool), typeof(ZoomWithWheelAndMoveBehavior), new PropertyMetadata(default(bool), (d, e) =>
             {
                 ZoomWithWheelAndMoveBehavior control = d as ZoomWithWheelAndMoveBehavior;

                 if (control == null) return;

                 control.RefreshReturn();

             }));


        void RefreshReturn()
        {
            if (zoomable == null) return;

            zoomable.Scale=1;
            zoomable.Offset =new Point(0,0);
        }

        /// <summary> 更新UseInParent刷新事件 </summary>
        void RefreshEvent()
        {
            if (this.parent == null || this.zoomable == null) return;

            if (!UseInParent)
            {
                parent.MouseWheel -= OnMouseWheel;
                parent.MouseMove -= OnMouseMove;
            }
            else
            {
                zoomable.MouseWheel -= OnMouseWheel;
                zoomable.MouseMove -= OnMouseMove;
            }

            if (UseInParent)
            {
                parent.MouseWheel += OnMouseWheel;
                parent.MouseMove += OnMouseMove;
            }
            else
            {
                zoomable.MouseWheel += OnMouseWheel;
                zoomable.MouseMove += OnMouseMove;
            }
        }

        void RefreshLocation()
        {
            if (this.zoomable == null) return;
            if (this.IsCenterInZoom)
            {
                var width = this.zoomable.ActualWidth - this.AssociatedObject.Width;

                var height = this.zoomable.ActualHeight - this.AssociatedObject.Height;

                Canvas.SetTop(this.AssociatedObject, height / 2);

                Canvas.SetLeft(this.AssociatedObject, width / 2);
            }
            else
            {
                Canvas.SetTop(this.AssociatedObject, 0);

                Canvas.SetLeft(this.AssociatedObject, 0);
            }
        }


        protected override void OnAttached()
        {
            parent = AssociatedObject.GetParent<Grid>();

            parent.Children.Remove(AssociatedObject);

            zoomable = new ZoomableCanvas();

            zoomable.Children.Add(AssociatedObject);

            zoomable.Loaded += Zoomable_Loaded;

            parent.Children.Add(zoomable);

            if (UseInParent)
            {
                parent.MouseWheel += OnMouseWheel;
                parent.MouseMove += OnMouseMove;
            }
            else
            {
                zoomable.MouseWheel += OnMouseWheel;
                zoomable.MouseMove += OnMouseMove;
            }
        }

        private void Zoomable_Loaded(object sender, RoutedEventArgs e)
        {
            this.RefreshLocation();
        }

        protected override void OnDetaching()
        {
            if (UseInParent)
            {
                parent.MouseWheel -= OnMouseWheel;
                parent.MouseMove -= OnMouseMove;
            }
            else
            {
                zoomable.MouseWheel -= OnMouseWheel;
                zoomable.MouseMove -= OnMouseMove;
            }

            zoomable.Loaded -= Zoomable_Loaded;
        }

        private void OnMouseWheel(object sender, MouseWheelEventArgs e)
        {

            var x = Math.Pow(2, e.Delta / 3.0 / Mouse.MouseWheelDeltaForOneLine);
            zoomable.Scale *= x;

            // Adjust the offset to make the point under the mouse stay still.
            var position = (Vector)e.GetPosition(parent);
            zoomable.Offset = (Point)((Vector)(zoomable.Offset + position) * x - position);

            e.Handled = true;
        }

        private Point LastMousePosition;

        private void OnMouseMove(object sender, MouseEventArgs e)
        {
            var position = e.GetPosition(this.parent);

            if (e.LeftButton == MouseButtonState.Pressed)
            {
                this.zoomable.Offset -= position - LastMousePosition;
            }
            LastMousePosition = position;
        }
    }

2、如下设置Xaml

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="50"/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <h:Row>
            <h:FCheckBox x:Name="cbx_inparent" Content="UseInParent" IsChecked="True"/>
            <h:FCheckBox  x:Name="cbx_center"  Content="IsCenterInZoom" Grid.Column="1" IsChecked="True"/>
            <h:FCheckBox  x:Name="cbx_return"  Content="Return" Grid.Column="2" IsChecked="True"/>

            <Label Style="{StaticResource S.Label.Flash}" Content="提示:尝试鼠标拖动和鼠标滚轮进行操作" HorizontalAlignment="Left" Foreground="Red" Grid.Column="3" Grid.ColumnSpan="3" FontSize="{StaticResource S.FontSize.Header}"/>
        </h:Row>

        <Grid ClipToBounds="True" Background="Transparent" Grid.Row="1">
            <h:ObjectPropertyForm Grid.Row="1" Title="学生信息"  SelectObject="{StaticResource S.Student.HeBianGu}">
                <h:Interaction.Behaviors>
                    <h:ZoomWithWheelAndMoveBehavior UseInParent="{Binding ElementName=cbx_inparent,Path=IsChecked,Mode=TwoWay}" 
                                                    IsCenterInZoom="{Binding ElementName=cbx_center,Path=IsChecked,Mode=TwoWay}"
                                                    IsReturn="{Binding ElementName=cbx_return,Path=IsChecked,Mode=TwoWay}"/>
                </h:Interaction.Behaviors>
            </h:ObjectPropertyForm>
        </Grid>
    </Grid>

 其中行为代码如下:

  <h:Interaction.Behaviors>
                    <h:ZoomWithWheelAndMoveBehavior UseInParent="{Binding ElementName=cbx_inparent,Path=IsChecked,Mode=TwoWay}" 
                                                    IsCenterInZoom="{Binding ElementName=cbx_center,Path=IsChecked,Mode=TwoWay}"
                                                    IsReturn="{Binding ElementName=cbx_return,Path=IsChecked,Mode=TwoWay}"/>
                </h:Interaction.Behaviors>

 

通过以上几部可以实现Zoom效果

其中Zoom控件部分使用的开源项目特此说明:

https://github.com/mdrabick/StiZoomableCanvas

 

五、下载地址

GitHub下载地址:https://github.com/HeBianGu/WPF-ControlBase.git

 

发布了76 篇原创文章 · 获赞 33 · 访问量 7万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章