示例: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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章