C# 如何从LiveCharts轴获取轴大小(以像素为单位),以确定轴上的自定义分隔步数?
我正在使用的WinForms版本在.NET应用程序中绘制一系列数据,作为线系列。我希望能够根据轴的长度(以像素为单位)调整X轴上显示的“刻度”数。到目前为止,我还不能确定轴的实际长度。在运行时检查时,C# 如何从LiveCharts轴获取轴大小(以像素为单位),以确定轴上的自定义分隔步数?,c#,.net,winforms,livecharts,C#,.net,Winforms,Livecharts,我正在使用的WinForms版本在.NET应用程序中绘制一系列数据,作为线系列。我希望能够根据轴的长度(以像素为单位)调整X轴上显示的“刻度”数。到目前为止,我还不能确定轴的实际长度。在运行时检查时,轴对象的高度和宽度为NaN,因此我的方法无法计算正确的刻度数(或步数) 所以,我的问题是,如何获得屏幕上显示的轴对象的正确大小(以像素为单位) 到目前为止,我的代码是: Form方法调用Chart类方法,根据所需的像素间距获取刻度数,并在轴上设置刻度间距: private static void U
轴
对象的高度
和宽度
为NaN
,因此我的方法无法计算正确的刻度数(或步数)
所以,我的问题是,如何获得屏幕上显示的轴对象的正确大小(以像素为单位)
到目前为止,我的代码是:
Form方法调用Chart
类方法,根据所需的像素间距获取刻度数,并在轴上设置刻度间距:
private static void UpdateChainageTickSpacing()
{
Axis chainageAxis = Chart.GetAxisByName(AxisOrientation.X, "Chainage");
int numTicks = Chart.GetNumTicksByPixelSpacing(chainageAxis, 40);
Chart.SetTickSpacing(chainageAxis, numTicks, 0);
}
在图表中
类:
public static void SetTickSpacing(Axis axis, int numTicks, int precision)
{
double maxValue = double.MinValue;
double minValue = double.MaxValue;
foreach (Series series in AllSeries)
{
maxValue = Math.Max(GetMaxValue(series, GetAxisOrientation(axis)), maxValue);
minValue = Math.Min(GetMinValue(series, GetAxisOrientation(axis)), minValue);
}
double range = maxValue - minValue;
double spacing = range / numTicks;
spacing = Math.Round(spacing / 10, precision) * 10;
axis.Separator.Step = spacing;
}
public static int GetNumTicksByPixelSpacing(Axis axis, int pixelSpacing)
{
double pixelSize;
if (GetAxisOrientation(axis) == AxisOrientation.X)
{
int index = GetAxisIndexByName(GetAxisCollection(AxisOrientation.X), axis.Name);
pixelSize = cartesianChart.AxisX[index].Width; // this returns NaN
}
else
{
int index = GetAxisIndexByName(GetAxisCollection(AxisOrientation.Y), axis.Name);
pixelSize = cartesianChart.AxisY[index].Height; // this returns NaN
}
return (int)Math.Round(pixelSize / pixelSpacing);
}
图表有两个Canvas
元素:父Canvas
包含图例、章节等图表元素,另一个子Canvas
作为实际打印区域,以承载打印的图形
轴长度(x和y)等于绘图区域的尺寸(宽度和高度)
您可以通过CartesianChart.Content
属性引用父级canvas
来访问绘图画布:
您需要等到所有元素都添加到绘图画布后,才能获得其最终大小
图表本身不公开在内容布局完成时发出通知的事件。因此,您必须收听绘图画布的ui元素.LayoutUpdated
事件
要实现这一点,您需要从窗口.ContentRendered
或窗口.Loaded
事件处理程序订阅Canvas.LayoutUpdated
事件。由于您希望忽略尽可能多的冗余布局更新,因此最后引发的Window.ContentRendered
事件在这种情况下是最好的
UIElement.LayoutUpdated
在每次布局过程(如调整大小或Canvas)中都会引发。子元素
集合操作(如添加/移动/删除子元素)非常频繁,因此需要进行一些优化以减少重复计算
main window.xaml
<Window>
<CartesianChart x:Name="Chart" />
</Window>
MainWindow.xaml.cs
partial class MainWindow: Window
{
public MainWindow()
{
InitializeComponent();
this.ContentRendered += OnContentRendered;
}
private void OnContentRendered(object sender, EventArgs e)
{
this.ContentRendered -= OnContentRendered;
var canvas = this.Chart.Content as Canvas;
var plotCanvas = canvas.Children.OfType<Canvas>().FirstOrDefault();
plotCanvas.LayoutUpdated += GetAxisXLengthOnLayoutUpdated;
}
// Will be called very often
// (on every layout pass of the Canvas sender like on resize or add/move/remove child)
private void GetAxisXLengthOnLayoutUpdated(object sender, EventArgs e)
{
var plotCanvas = sender as Canvas;
// If this is a one time operation, unsubscribe from LayoutUpdated event
plotCanvas.LayoutUpdated -= GetAxisXLengthOnLayoutUpdated;
// The length of the x-axis is equal to the final width of the plot area
var actualAxisXLength = plotCanvas.ActualWidth;
}
}
部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
this.ContentRendered+=OnContentRendered;
}
私有void onContenterned(对象发送方、事件参数e)
{
this.ContentRendered-=OnContentRendered;
var canvas=this.Chart.Content作为画布;
var plotCanvas=canvas.Children.OfType().FirstOrDefault();
plotCanvas.LayoutUpdated+=GetAxisXlengtonLayoutUpdated;
}
//我们会经常打电话
//(在画布发送器的每个布局过程上,如调整大小或添加/移动/移除子对象)
私有void GetAxisXlengtonLayoutUpdated(对象发送方,事件参数e)
{
var plotCanvas=发送方作为画布;
//如果这是一次性操作,请取消订阅LayoutUpdated事件
plotCanvas.LayoutUpdated-=GetAxisXlengtonLayoutUpdated;
//x轴的长度等于绘图区域的最终宽度
var actualAxisXLength=plotCanvas.ActualWidth;
}
}
我怀疑这是正确的方法。图表元素都是相对于轴值的。您应该观察轴值范围/缩放以确定节数…我这样做是为了处理窗体大小调整,并确保根据图表控件本身的宽度显示适当数量的分隔符步数。我将按照您下面的回答中所述,对画布元素进行一次游戏,看看它是如何工作的,因为我不认为使用值范围和/或缩放将提供我所需要的。也许您可以将图表设置为固定大小,并将其包装到ScrollViewer中。为了提供更多细节或更高的分辨率/精度,用户应使用缩放而不是调整窗体大小。如果在相同的值范围内更改分隔符的数量,则步骤将变为新值。如果axis的范围是100,你有10个台阶,那么我知道每根棒的增量是10。这有助于我对图形有一个初步的了解。现在,当我将窗口的大小增加一倍时,您可以将条数增加一倍,每个条现在增加5,因为范围保持不变(100)。这可能令人困惑。除非我明确地改变网格的比例,否则我希望分离器的重量总是相同的(在本例中为10)。我认为关键是这些分隔符与轴值相关,而不是轴元素的渲染像素长度。你只是给它一个新的和意想不到的意义。但我想你知道你想要什么。当然,我明白你的意思。我认为,出于我的目的,随着图表宽度的增加,最好增加X轴上的分隔符数量,但我完全明白你的意思。谢谢你对下面答案的帮助,它把它带到了需要的地方。