我创建了一个图形 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));
}
}
}
答案 0 :(得分:1)
将折线的StrokeLineJoin
设置为Bevel
或Round
以避免出现“尖角”。
var p = new Polygon
{
Fill = Fill,
Stroke = Stroke,
StrokeLineJoin = PenLineJoin.Round
};