如何从 LiveCharts 轴获取轴大小(以像素为单位)以确定轴上的自定义分隔符步数?
How do I get the Axis size, in pixels, from a LiveCharts Axis in order to determine a custom number of Separator steps on the axis?
我正在使用 LiveCharts 的 WinForms 版本在我的 .NET 应用程序中绘制一系列数据,作为 LineSeries。我希望能够根据轴的长度(以像素为单位)调整 X 轴上显示的 'ticks' 的数量。到目前为止,我无法确定轴的实际长度。在运行时检查时,Axis
对象有一个 Height
和一个 NaN
的 Width
,所以我的方法无法计算正确的滴答数(或步数)。
所以,我的问题是,如何获得屏幕上显示的 Axis
对象的正确大小(以像素为单位)?
到目前为止我的代码:
表单方法调用 Chart
class 方法以根据所需的像素间距获取刻度数并在轴上设置刻度间距:
private static void UpdateChainageTickSpacing()
{
Axis chainageAxis = Chart.GetAxisByName(AxisOrientation.X, "Chainage");
int numTicks = Chart.GetNumTicksByPixelSpacing(chainageAxis, 40);
Chart.SetTickSpacing(chainageAxis, numTicks, 0);
}
在Chart
class:
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
来访问绘图 canvas
您需要等到所有元素都添加到绘图中 canvas 才能获得最终大小。
图表本身不公开通知内容布局何时完成的事件。所以你要听剧情canvas.
的UIElement.LayoutUpdated
事件
为此,您需要从 Window.ContentRendered
或 Window.Loaded
事件处理程序订阅 Canvas.LayoutUpdated
事件。由于您想尽可能多地忽略冗余布局更新,因此最后引发的 Window.ContentRendered
事件在这种情况下是最好的。
UIElement.LayoutUpdated
在每个布局过程中都会引发,例如调整大小或 Canvas.Children
集合操作,例如 add/move/remove 子元素,这很常见,因此需要一些优化来减少冗余 re-calculations.
MainWindow.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;
}
}
我正在使用 LiveCharts 的 WinForms 版本在我的 .NET 应用程序中绘制一系列数据,作为 LineSeries。我希望能够根据轴的长度(以像素为单位)调整 X 轴上显示的 'ticks' 的数量。到目前为止,我无法确定轴的实际长度。在运行时检查时,Axis
对象有一个 Height
和一个 NaN
的 Width
,所以我的方法无法计算正确的滴答数(或步数)。
所以,我的问题是,如何获得屏幕上显示的 Axis
对象的正确大小(以像素为单位)?
到目前为止我的代码:
表单方法调用 Chart
class 方法以根据所需的像素间距获取刻度数并在轴上设置刻度间距:
private static void UpdateChainageTickSpacing()
{
Axis chainageAxis = Chart.GetAxisByName(AxisOrientation.X, "Chainage");
int numTicks = Chart.GetNumTicksByPixelSpacing(chainageAxis, 40);
Chart.SetTickSpacing(chainageAxis, numTicks, 0);
}
在Chart
class:
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
来访问绘图 canvas
您需要等到所有元素都添加到绘图中 canvas 才能获得最终大小。
图表本身不公开通知内容布局何时完成的事件。所以你要听剧情canvas.
的UIElement.LayoutUpdated
事件
为此,您需要从 Window.ContentRendered
或 Window.Loaded
事件处理程序订阅 Canvas.LayoutUpdated
事件。由于您想尽可能多地忽略冗余布局更新,因此最后引发的 Window.ContentRendered
事件在这种情况下是最好的。
UIElement.LayoutUpdated
在每个布局过程中都会引发,例如调整大小或 Canvas.Children
集合操作,例如 add/move/remove 子元素,这很常见,因此需要一些优化来减少冗余 re-calculations.
MainWindow.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;
}
}