WPF绘图按比例缩放了一个已填充的封闭多边形

时间:2018-07-24 19:58:08

标签: c# wpf

我创建了一个图形 UserControl ,该图形绘制了带有网格线的图形。 设计了用户控件,以便调用方一次添加1个值,然后用户控件将其添加到包含最后60个条目的存储桶中。通过设置TabulaData属性来添加该值。 给定的数据元素范围为0.0-100.0

最终效果是,一旦达到60个元素,添加新值后图形就会滚动。

在GUI的左侧,我有一个列表框,其中包含按比例缩小的图形。在列表中选择图形后,将绘制完整尺寸的版本。

创建完整尺寸的图形时,它会完美绘制。在“列表框”中绘制时,有时会在网格线之外绘制一条线,因此不应绘制该线。

通过创建一个封闭的填充多边形来创建图形。 我已经检查了几次数学,并且不确定为什么有时在列表框中绘制错误。在列表框中,图形为44x50,小于数据元素的数量,因此按比例缩小。

问题是,如何防止缩小版本的绘制超出网格线?

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Shapes;
using Binding = System.Windows.Data.Binding;
using Point = System.Windows.Point;
using Brush = System.Windows.Media.Brush;
using ToolTip = System.Windows.Controls.ToolTip;

namespace GraphContainer
{
    /// <summary>
    /// Interaction logic for Graph.xaml
    /// </summary>
    public partial class Graph : INotifyPropertyChanged
    {
        public Graph()
        {
            InitializeComponent();

            SizeChanged += (sender, args) =>
            {
                SafeCreateGraph();
            };
        }


        private bool _drawGrid = true;

        public bool DrawGrid
        {
            get { return _drawGrid; }
            set
            {
                _drawGrid = value;
                OnPropertyChanged();
            }
        }

        private Brush _gridBrush = new SolidColorBrush(Color.FromRgb(0x77, 0x77, 0x77));

        public Brush GridBrush
        {
            get { return _gridBrush; }
            set
            {
                _gridBrush = value;
                OnPropertyChanged();
            }
        }

        private Brush _fill = new SolidColorBrush(Colors.Transparent);

        public Brush Fill
        {
            get { return _fill; }
            set
            {
                _fill = value;
                OnPropertyChanged();
                InvalidateVisual();
            }
        }

        private Brush _stroke = new SolidColorBrush(Colors.Black);

        public Brush Stroke
        {
            get { return _stroke; }
            set
            {
                _stroke = value;
                OnPropertyChanged();
                InvalidateVisual();

                GraphBorder.BorderBrush = value;
            }
        }

        private double _sampleSize = 60;

        public double SampleSize
        {
            get { return _sampleSize; }
            set
            {
                _sampleSize = value;
                OnPropertyChanged();
                SafeCreateGraph();
            }
        }

        private double _tabulaData;

        public double TabulaData
        {
            get { return _tabulaData; }
            set
            {
                _tabulaData = value;

                TabulaList.Insert(0, value);
                while (TabulaList.Count > SampleSize)
                {
                    TabulaList.RemoveAt(TabulaList.Count -1);
                }
                SafeCreateGraph();
            }
        }

        public void ResetData()
        {
            TabulaList.Clear();
            SafeCreateGraph();
        }

        private readonly List<double> _tabulaList = new List<double>();

        public List<double> TabulaList
        {
            get { return _tabulaList; }
            set
            {
                _tabulaList.Clear();

                foreach (var d in value)
                {
                    _tabulaList.Add(d);
                }
                OnPropertyChanged();
                SafeCreateGraph();
            }
        }

        private void CreateGrid()
        {
            if (ActualHeight  < 1 || ActualWidth < 1)
                return;

            var drawHeight = ActualHeight - 2;
            var drawWidth = ActualWidth - 2;

            var widthscale = Math.Max(10, drawWidth / (SampleSize - 1));
            var yscale = Math.Max(10, drawHeight * .05); // 5 %

            for (var x = 0.0; x < drawWidth; x += widthscale)
            {
                var l = new Line
                {
                    Stroke = GridBrush,
                    X1 = x,
                    X2 = x,
                    Y1 = 0,
                    Y2 = drawHeight
                };

                GraphCanvas.Children.Add(l);
            }

            for (var y = 0.0; y < drawHeight; y += yscale)
            {
                var l = new Line
                {
                    Stroke = GridBrush,
                    X1 = 0,
                    X2 = drawWidth,
                    Y1 = y,
                    Y2 = y
                };

                GraphCanvas.Children.Add(l);
            }
        }

        private string _graphHelpText = "";

        public string GraphHelpText
        {
            get { return _graphHelpText; }
            set
            {
                _graphHelpText = value;
                OnPropertyChanged();
            }
        }

        private void SafeCreateGraph()
        {
            if (Dispatcher.CheckAccess())
            {
                CreateGraph();
            }
            else
            {
                Dispatcher.BeginInvoke(new Action(CreateGraph));
            }
        }

        private void CreateGraph()
        {
            GraphCanvas.Children.Clear();

            if (ActualHeight < 1 || ActualWidth < 1)
                return;


            if (DrawGrid)
            {
                CreateGrid();
            }

            if (TabulaList.Count > 1)
            {
                var p = new Polygon { Fill = Fill, Stroke = Stroke };
                if (DrawGrid)
                {
                    var t = new ToolTip
                    {
                        DataContext = this,
                        Placement = PlacementMode.Mouse
                    };
                    var binding = new Binding(nameof(GraphHelpText))
                    {
                        Mode = BindingMode.OneWay,
                        UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
                    };
                    t.SetBinding(ContentProperty, binding);
                    p.ToolTip = t;
                    ToolTipService.SetInitialShowDelay(p, 0);
                    ToolTipService.SetBetweenShowDelay(p, 0);
                    ToolTipService.SetShowDuration(p, 120000);
                }

                var drawHeight = ActualHeight - 2;
                var drawWidth = ActualWidth - 2;

                var widthscale = drawWidth / (SampleSize - 1);
                var yscale = drawHeight / 100.0;
                p.MouseMove += (sender, args) =>
                {
                    try
                    {
                        var point = args.GetPosition(p);
                        var time = (int) (SampleSize - 1) - (int) (point.X / widthscale + .5);
                        var tabula = TabulaList[time] / 100;
                        var seconds = time == 1 ? "second" : "seconds";
                        GraphHelpText = $"{time} {seconds} {tabula:P}";
                    }
#pragma warning disable CC0004 // Catch block cannot be empty
                    catch (ExternalException)
                    {
                        // ignored
                    }
#pragma warning restore CC0004 // Catch block cannot be empty
                };

                const int min = 0;
                var xmax = drawWidth;
                var ymax = drawHeight;

                var x = 0.0;
                for (var i = 0; i < TabulaList.Count; i++)
                {
                    var tabula = TabulaList[i];

                    x = drawWidth - i * widthscale;
                    x = Math.Max(min, Math.Min(xmax, x));
                    var y = drawHeight - tabula * yscale;
                    y = Math.Max(min, Math.Min(ymax, y));

                    p.Points.Add(new Point(x, y));
                }

                p.Points.Add(new Point(x, ymax));
                p.Points.Add(new Point(xmax, ymax));

                GraphCanvas.Children.Add(p);
            }

            InvalidateVisual();
        }

        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

1 个答案:

答案 0 :(得分:1)

将折线的StrokeLineJoin设置为BevelRound以避免出现“尖角”。

var p = new Polygon
{
    Fill = Fill,
    Stroke = Stroke,
    StrokeLineJoin = PenLineJoin.Round
};