WPF自定义可移动用户控件,由垂直线和水平线组成

时间:2018-11-24 03:41:18

标签: c# wpf

首先,我需要画一条垂直线和一条水平线。我使用GeometryGroup来实现这一点。它看起来像这样

enter image description here

自定义类代码:

public class QuadrantGate1 : Shape
{
    #region  Constructors
    /// <summary>
    /// Instantiate a new instance of a line.
    /// </summary>
    public QuadrantGate1()
    {
    }
    #endregion

    #region Dynamic Properties
    public double VerticalY1
    {
        get { return (double)GetValue(VerticalY1Property); }
        set { SetValue(VerticalY1Property, value); }
    }
    // Using a DependencyProperty as the backing store for VerticalY1.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty VerticalY1Property =
        DependencyProperty.Register("VerticalY1", typeof(double), typeof(QuadrantGate1), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
    public double VerticalY2
    {
        get { return (double)GetValue(VerticalY2Property); }
        set { SetValue(VerticalY2Property, value); }
    }
    // Using a DependencyProperty as the backing store for VerticalY2.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty VerticalY2Property =
        DependencyProperty.Register("VerticalY2", typeof(double), typeof(QuadrantGate1), new FrameworkPropertyMetadata(256.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
    public double VerticalX
    {
        get { return (double)GetValue(VerticalXProperty); }
        set { SetValue(VerticalXProperty, value); }
    }
    // Using a DependencyProperty as the backing store for VerticalX1.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty VerticalXProperty =
        DependencyProperty.Register("VerticalX", typeof(double), typeof(QuadrantGate1), new FrameworkPropertyMetadata(128.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
    public double HorizontalX1
    {
        get { return (double)GetValue(HorizontalX1Property); }
        set { SetValue(HorizontalX1Property, value); }
    }
    // Using a DependencyProperty as the backing store for HorizontalX1.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty HorizontalX1Property =
        DependencyProperty.Register("HorizontalX1", typeof(double), typeof(QuadrantGate1), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
    public double HorizontalX2
    {
        get { return (double)GetValue(HorizontalX2Property); }
        set { SetValue(HorizontalX2Property, value); }
    }
    // Using a DependencyProperty as the backing store for HorizontalX2.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty HorizontalX2Property =
        DependencyProperty.Register("HorizontalX2", typeof(double), typeof(QuadrantGate1), new FrameworkPropertyMetadata(256.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
    public double HorizontalY
    {
        get { return (double)GetValue(HorizontalYProperty); }
        set { SetValue(HorizontalYProperty, value); }
    }
    // Using a DependencyProperty as the backing store for HorizontalY.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty HorizontalYProperty =
        DependencyProperty.Register("HorizontalY", typeof(double), typeof(QuadrantGate1), new FrameworkPropertyMetadata(128.0, FrameworkPropertyMetadataOptions.AffectsMeasure));

    #endregion

    #region Protected Methods and Properties
    protected override Geometry DefiningGeometry
    {
        get
        {
            _geometryGroup = new GeometryGroup();
            _geometryGroup.FillRule = FillRule.Nonzero;
            DrawTwoLinesGeometry(_geometryGroup);

            _path = new Path();
            _path.Data = _geometryGroup;
            return _geometryGroup;

        }
    }

    private void DrawTwoLinesGeometry(GeometryGroup geometryGroup)
    {
        try
        {
            _lineGeometry1 = new LineGeometry()
            {
                StartPoint = new Point { X = HorizontalX1, Y = HorizontalY },
                EndPoint = new Point { X = HorizontalX2, Y = HorizontalY }
            };
            _lineGeometry2 = new LineGeometry()
            {
                StartPoint = new Point { X = VerticalX, Y = VerticalY1 },
                EndPoint = new Point { X = VerticalX, Y = VerticalY2 }
            };
            _geometryGroup.Children.Add(_lineGeometry1);
            _geometryGroup.Children.Add(_lineGeometry2);
        }
        catch (Exception e)
        {
        }

    }
    #endregion

    #region Private Methods and Members
    private GeometryGroup _geometryGroup;

    private LineGeometry _lineGeometry1;
    private LineGeometry _lineGeometry2;
    private Path _path;
    #endregion
}

xaml代码:

enter image description here

第二,我需要移动两行。鼠标在水平线上时,可以上下移动水平线,垂直线保持静止。

当鼠标在垂直线上时,垂直线可以向左或向右移动,水平线保持静止。

当鼠标位于两条线的交叉点上时,两条线都可以移动,水平线可以上下移动,垂直线可以左右移动。

我想先移动两行,所以自定义类代码:

public class QuadrantGate1 : Shape
{
    #region  Constructors
    /// <summary>
    /// Instantiate a new instance of a line.
    /// </summary>
    public QuadrantGate1()
    {
        this.MouseDown += QuadrantGate_MouseDown;
        this.MouseMove += QuadrantGate_MouseMove;
        this.MouseLeftButtonUp += QuadrantGate_MouseLeftButtonUp;
    }
    #endregion

    #region Dynamic Properties
    public double VerticalY1
    {
        get { return (double)GetValue(VerticalY1Property); }
        set { SetValue(VerticalY1Property, value); }
    }
    // Using a DependencyProperty as the backing store for VerticalY1.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty VerticalY1Property =
        DependencyProperty.Register("VerticalY1", typeof(double), typeof(QuadrantGate1), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
    public double VerticalY2
    {
        get { return (double)GetValue(VerticalY2Property); }
        set { SetValue(VerticalY2Property, value); }
    }
    // Using a DependencyProperty as the backing store for VerticalY2.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty VerticalY2Property =
        DependencyProperty.Register("VerticalY2", typeof(double), typeof(QuadrantGate1), new FrameworkPropertyMetadata(256.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
    public double VerticalX
    {
        get { return (double)GetValue(VerticalXProperty); }
        set { SetValue(VerticalXProperty, value); }
    }
    // Using a DependencyProperty as the backing store for VerticalX1.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty VerticalXProperty =
        DependencyProperty.Register("VerticalX", typeof(double), typeof(QuadrantGate1), new FrameworkPropertyMetadata(128.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
    public double HorizontalX1
    {
        get { return (double)GetValue(HorizontalX1Property); }
        set { SetValue(HorizontalX1Property, value); }
    }
    // Using a DependencyProperty as the backing store for HorizontalX1.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty HorizontalX1Property =
        DependencyProperty.Register("HorizontalX1", typeof(double), typeof(QuadrantGate1), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
    public double HorizontalX2
    {
        get { return (double)GetValue(HorizontalX2Property); }
        set { SetValue(HorizontalX2Property, value); }
    }
    // Using a DependencyProperty as the backing store for HorizontalX2.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty HorizontalX2Property =
        DependencyProperty.Register("HorizontalX2", typeof(double), typeof(QuadrantGate1), new FrameworkPropertyMetadata(256.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
    public double HorizontalY
    {
        get { return (double)GetValue(HorizontalYProperty); }
        set { SetValue(HorizontalYProperty, value); }
    }
    // Using a DependencyProperty as the backing store for HorizontalY.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty HorizontalYProperty =
        DependencyProperty.Register("HorizontalY", typeof(double), typeof(QuadrantGate1), new FrameworkPropertyMetadata(128.0, FrameworkPropertyMetadataOptions.AffectsMeasure));

    #endregion

    #region Protected Methods and Properties
    protected override Geometry DefiningGeometry
    {
        get
        {
            _geometryGroup = new GeometryGroup();
            _geometryGroup.FillRule = FillRule.Nonzero;
            DrawTwoLinesGeometry(_geometryGroup);
            _path = new Path();
            _path.Data = _geometryGroup;
            return _geometryGroup;
        }
    }

    private void DrawTwoLinesGeometry(GeometryGroup geometryGroup)
    {
        try
        {
            _lineGeometry1 = new LineGeometry()
            {
                StartPoint = new Point { X = HorizontalX1, Y = HorizontalY },
                EndPoint = new Point { X = HorizontalX2, Y = HorizontalY }
            };
            _lineGeometry2 = new LineGeometry()
            {
                StartPoint = new Point { X = VerticalX, Y = VerticalY1 },
                EndPoint = new Point { X = VerticalX, Y = VerticalY2 }
            };
            _geometryGroup.Children.Add(_lineGeometry1);
            _geometryGroup.Children.Add(_lineGeometry2);
        }
        catch (Exception e)
        {
        }

    }
    #endregion

    #region Events Methods
    private void QuadrantGate_MouseDown(object sender, MouseButtonEventArgs e)
    {
        if (e.OriginalSource.GetType() == typeof(QuadrantGate1))
        {
            this.mouseBefore = e.GetPosition(this);

            QuadrantGate1 quadrantGate = (QuadrantGate1)e.OriginalSource;
            startBefore.X = VerticalX;
            startBefore.Y = HorizontalY;
            quadrantGate.CaptureMouse();

        }

    }

    GeometryCollection GeometryGroupChildren(GeometryGroup geometryGroup)
    {
        GeometryCollection geometries = new GeometryCollection();
        if (geometryGroup == null)
            return null;
        else
        {
            geometries = geometryGroup.Children;
            return geometries;
        }
    }

    private void QuadrantGate_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            if (e.OriginalSource != null && e.OriginalSource.GetType() == typeof(QuadrantGate1))
            {
                QuadrantGate1 quadrantGate = (QuadrantGate1)e.OriginalSource;
                Point p = e.GetPosition(this);
                VerticalX = startBefore.X + (p.X - mouseBefore.X);
                HorizontalY = startBefore.Y + (p.Y - mouseBefore.Y);
            }
        }
    }
    private void QuadrantGate_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        if (e.OriginalSource.GetType() == typeof(QuadrantGate1))
        {
            QuadrantGate1 quadrantGate = (QuadrantGate1)e.OriginalSource;
            quadrantGate.ReleaseMouseCapture();
        }

    }

    #endregion

    #region Private Methods and Members
    private GeometryGroup _geometryGroup;
    private LineGeometry _lineGeometry1;
    private LineGeometry _lineGeometry2;
    private Path _path;

    Point mouseBefore;
    Point startBefore;
    #endregion
}

但是这两行并没有按照我的意愿移动。这两行的移动与鼠标不一致。

enter image description here

奇怪的是,如果注释掉这些行_geometryGroup.Children.Add(_lineGeometry1);或此_geometryGroup.Children.Add(_lineGeometry2);之一,则其余行可以成功移动。这是水平线:

enter image description here

和垂直线:

enter image description here

1 个答案:

答案 0 :(得分:0)

通过实现代码,我看到了渲染问题,您还可以看到是否只是按下鼠标并最小化屏幕,再次打开它就可以看到行移到了另一个位置。

您可以尝试使用StreamGeometryContext代替GeometryGroup,下面是代码DefiningGeometry get Property。

        protected override Geometry DefiningGeometry
    {
        get
        {
            StreamGeometry geometry = new StreamGeometry();
            geometry.FillRule = FillRule.EvenOdd;

            using (StreamGeometryContext ctx = geometry.Open())
            {

                ctx.BeginFigure(new Point(HorizontalX1, HorizontalY), true /* is filled */, true /* is closed */);

                ctx.LineTo(new Point(HorizontalX2, HorizontalY), true /* is stroked */, false /* is smooth join */);

                ctx.BeginFigure(new Point(VerticalX, VerticalY1), true /* is filled */, true /* is closed */);

                ctx.LineTo(new Point(VerticalX, VerticalY2), true /* is stroked */, false /* is smooth join */);

            }
            //geometry.Freeze();

            _path = new Path();
            _path.Data = geometry;
            return geometry;
        }
    }