C# 如何从LiveCharts轴获取轴大小(以像素为单位),以确定轴上的自定义分隔步数?

C# 如何从LiveCharts轴获取轴大小(以像素为单位),以确定轴上的自定义分隔步数?,c#,.net,winforms,livecharts,C#,.net,Winforms,Livecharts,我正在使用的WinForms版本在.NET应用程序中绘制一系列数据,作为线系列。我希望能够根据轴的长度(以像素为单位)调整X轴上显示的“刻度”数。到目前为止,我还不能确定轴的实际长度。在运行时检查时,轴对象的高度和宽度为NaN,因此我的方法无法计算正确的刻度数(或步数) 所以,我的问题是,如何获得屏幕上显示的轴对象的正确大小(以像素为单位) 到目前为止,我的代码是: Form方法调用Chart类方法,根据所需的像素间距获取刻度数,并在轴上设置刻度间距: private static void U

我正在使用的WinForms版本在.NET应用程序中绘制一系列数据,作为线系列。我希望能够根据轴的长度(以像素为单位)调整X轴上显示的“刻度”数。到目前为止,我还不能确定轴的实际长度。在运行时检查时,
对象的
高度
宽度
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轴上的分隔符数量,但我完全明白你的意思。谢谢你对下面答案的帮助,它把它带到了需要的地方。