自定义面板二

上篇文章中的面板是重写MeasureOverride()和 ArrangeOverride()方法,实现布局的,这次为了实现像ListBox控件一样,子元素可以按自定义轨迹拖动,这次就不用这两种方法,自定义方法。代码如下:

public class SemiCircalPanel:Canvas
    {
        [Category("面板设置")]// 元素最小宽度
        public double ChildWidth{ get { return (double)GetValue(ChildWidthProperty); }set { SetValue(ChildWidthProperty, value); }}
        public static readonly DependencyProperty ChildWidthProperty =
            DependencyProperty.Register("ChildWidth", typeof(double), typeof(SemiCircalPanel), new FrameworkPropertyMetadata(30.0, FrameworkPropertyMetadataOptions.AffectsArrange));

        [Category("面板设置")]// // 元素最小高度
        public double ChildHeight{ get { return (double)GetValue(ChildHeightProperty); }set { SetValue(ChildHeightProperty, value); } }
        public static readonly DependencyProperty ChildHeightProperty =
            DependencyProperty.Register("ChildHeight", typeof(double), typeof(SemiCircalPanel), new FrameworkPropertyMetadata(20.0, FrameworkPropertyMetadataOptions.AffectsArrange));

        private Point start = new Point(0, 0);
        private bool IsMouseDown = false;
        public SemiCircalPanel()
        {
            BrushConverter brushConverter = new BrushConverter();
            Brush brush = (Brush)brushConverter.ConvertFromString("#01000000");
            this.Background = brush;//背景不可设置成完全透明,否则会影响拖动效果
            this.Loaded+=new RoutedEventHandler(SemiCircalPanel_Loaded);
            this.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(PanelControl_MouseDown);
            this.MouseMove += new System.Windows.Input.MouseEventHandler(PanelControl_MouseMove);
            this.MouseLeave += new System.Windows.Input.MouseEventHandler(PanelControl_MouseLeave);
            this.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(PanelControl_MouseUp);
        }


        private void SemiCircalPanel_Loaded(object sender, RoutedEventArgs e)
        {
                try
                {
                    SetUIElement();
                }
                catch (Exception ex)
                {
                    throw new Exception(ex.Message);
                }
        }


        public void AddChildren(UIElement e)
        {
            this.Children.Add(e);
            SetUIElement();
        }


        private void SetUIElement()
        {
            double a = this.Children.Count;
            for (int i = 0; i < a; i++)
            {
                PositionChild(i, this.RenderSize);
            }
        }


        /// <summary>
        /// 计算元素初始位置和大小
        /// </summary>
        /// <param name="index"></param>
        /// <param name="panelSize"></param>
        private void PositionChild(int index, Size panelSize)
        {
            if (this.Children.Count >= 2)
            {
                double ang = (double)index * (Math.PI / (this.Children.Count - 1)) + Math.PI / 2;  //取得对应位置的角度值
                var st = new ScaleTransform();
                this.Children[index].SetValue(Panel.ZIndexProperty, (int)(-Math.Cos(ang) * panelSize.Width)); //设置显示层次值,在Y坐标上值大图片的覆盖值小的图片 
                double newScale = 1 - (double)Math.Cos(ang);
                if (newScale >= 0)
                {                //根据角度确定椭圆轨迹上的坐标值
                    double myX = (double)Math.Cos(ang) * panelSize.Width + panelSize.Width - ChildWidth; //取得X轴坐标值
                    double myY = (double)Math.Sin(ang) * (panelSize.Height - ChildHeight) / 2 + (panelSize.Height - ChildHeight) / 2; //取得Y轴坐标值
                    st.ScaleX = newScale;
                    st.ScaleY = newScale;
                    this.Children[index].RenderTransform = st;
                    var fe = this.Children[index] as FrameworkElement;
                    if (fe != null)
                    {
                        fe.Tag = ang;
                        fe.Name = "E"+index.ToString();
                        fe.Width = newScale * ChildWidth;
                        fe.Height = newScale * ChildHeight;
                        Canvas.SetLeft(this.Children[index], myX);
                        Canvas.SetTop(this.Children[index], myY);
                    }
                }
            }
        }

        /// <summary>
        /// 鼠标按起时,重置标志值
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void PanelControl_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            IsMouseDown = false;
        }


        /// <summary>
        /// 鼠标离开时,重置标志值
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void PanelControl_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
        {
            IsMouseDown = false;
        }


        /// <summary>
        /// 鼠标移动时,根据Y值差值,计算元素新大小和位置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void PanelControl_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (IsMouseDown)
            {
                Point p = e.GetPosition((IInputElement) sender);
                double d_value = p.Y - start.Y;
                SetPosition(d_value);//重设元素大小和位置
                start = p;
            }
        }


        /// <summary>
        /// 重新设置元素大小和位置
        /// </summary>
        /// <param name="dValue"></param>
        private void SetPosition(double dValue)
        {
            double a = this.Children.Count;
            for (int index = 0; index < a; index++)
            {
                if (this.Children.Count >= 2)
                {
                    var fe = this.Children[index] as FrameworkElement;
                    double dangle = 0;
                    if (fe != null && fe.Tag != null)
                    {
                        double ang = 0;
                        if (dValue <= 0)
                        {
                            dangle = Math.Asin(-dValue / this.RenderSize.Width);
                            ang = (double)fe.Tag + dangle;
                        }
                        else
                        {
                            dangle = Math.Asin(dValue / this.RenderSize.Width);
                            ang = (double)fe.Tag - dangle;
                        }
                        var st = new ScaleTransform();
                        this.Children[index].RenderTransform = st;
                        this.Children[index].SetValue(Panel.ZIndexProperty,
                                                            (int)(-Math.Cos(ang) * this.RenderSize.Width));
                        //设置显示层次值,在Y坐标上值大图片的覆盖值小的图片 
                        double newScale = 1 - (double)Math.Cos(ang);
                        if (newScale >= 0)
                        {
                            //根据角度确定椭圆轨迹上的坐标值
                            double myX = (double)Math.Cos(ang) * this.RenderSize.Width +
                                         this.RenderSize.Width - ChildWidth; //取得X轴坐标值
                            double myY = (double)Math.Sin(ang) * (this.RenderSize.Height - ChildHeight) / 2 +
                                         (this.RenderSize.Height - ChildHeight) / 2; //取得Y轴坐标值
                            st.ScaleX = newScale;
                            st.ScaleY = newScale;
                            fe.Tag = ang;
                            fe.Width = newScale * ChildWidth;
                            fe.Height = newScale * ChildHeight;
                            Canvas.SetLeft(this.Children[index], myX);
                            Canvas.SetTop(this.Children[index], myY);
                        }
                    }
                }
            }
        }


        /// <summary>
        /// 鼠标按下时,记下点击时的位置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void PanelControl_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            IsMouseDown = true;
            start = e.GetPosition((IInputElement)sender);
        }
    }


到此,面板已完成。

猜你喜欢

转载自blog.csdn.net/feitiankoulan/article/details/22386831
今日推荐