.net - 自定义 LegendItem 时 ChartInvalidate 期间出现 NullReferenceException
问题描述
我在powershell中为IIS日志构建了一个图形引擎,点的大小由绘制的点数(50-50k)缩放。当尺寸很小时,图例会同时调整,所以我正在尝试调整图例中标记的大小。
我创建了一个事件函数:
$chart1_CustomizeLegend = {
Param([Object]$sender , [System.Windows.Forms.DataVisualization.Charting.CustomizeLegendEventArgs]$e )
try
{
if ($e.LegendItems.Count -gt 0)
{
Write-Host found $e.LegendItems.Count legend items
for ($i = 0 ; $i -lt $e.LegendItems.Count ; $i++)
{
write-host processing $i
if ($e.LegendItems[$i] -eq $null)
{
write-host item is null
}
else
{
write-host item is not null
}
#update marker size
$e.LegendItems[$i].MarkerSize=10
}
}
} catch [System.Exception] {
Write-Error "failed to customize legend-item"
$_ | Format-List -Force | Out-String | Write-Error
}
}#CustomizeLegend
并注册:
$custjob = Register-ObjectEvent -InputObject $chart1 -EventName CustomizeLegend -Action $chart1_CustomizeLegend
我可以看到它被调用了,但是它碰到了 catch 块:
未能自定义图例项
异常:System.NullReferenceException:对象引用未设置为对象的实例。在 System.Windows.Forms.DataVisualization.Charting.Chart.Invalidate() 在 System.Windows.Forms.DataVisualization.Charting.ChartPicture.Invalidate() 在 System.Windows.Forms.DataVisualization.Charting.ChartElementCollection`1.Invalidate()在 System.Windows.Forms.DataVisualization.Charting.ChartElement.Invalidate() 在 System.Windows.Forms.DataVisualization.Charting.Legend.Invalidate(Boolean invalidateLegendOnly) 在 CallSite.Target(Closure , CallSite , Object , Int32 ) TargetObject : CategoryInfo : 未指定: (:) [],
但在此之前它写出该项目不是空的,所以我知道我没有做任何空引用异常。这似乎是一个 .NET 问题,但很难确定。
它似乎在图表的 SaveImage 期间发生。
$ChartName = "IIS Response Time {0}-{1}, Series By Call Type, time-response scatter" -f $data.Folder,$data.File
Write-progress -status "Preparing $ChartName containing $($data.data.count) points" -activity "Preparing $ChartName, getting data"
$DataArray = $data.data |where {$_["time"]}| where $FilterSB | where $CoreFilterSB
$chart1 = New-object System.Windows.Forms.DataVisualization.Charting.Chart
$chart1.Width = 1200*$GraphScale
$chart1.Height = 800*$GraphScale
$chart1.BackColor = [System.Drawing.Color]::White
# title
$chart1.Titles.Add(("{0} ({1} of {2} points) " -f $ChartName, @($DataArray).Count, $data.data.count)) > $null
$chart1.Titles[0].Font = "Arial,{0}pt" -f (8*$GraphScale)
$chart1.Titles[0].Alignment = "topLeft"
# chart area
$chartarea = New-Object System.Windows.Forms.DataVisualization.Charting.ChartArea
$chartarea.Name = "ChartArea1"
$chartarea.AxisY.Title = "Response time (MS)"
$chartarea.AxisX.Title = "Time"
$chartarea.AxisY.LogarithmBase = 2
#$chartarea.axisy.IntervalAutoMode = [System.Windows.Forms.DataVisualization.Charting.IntervalAutoMode]::FixedCount
$chartarea.AxisX.Interval = 60
$chartarea.AxisX.IntervalType = [System.Windows.Forms.DataVisualization.Charting.DateTimeIntervalType]::Minutes
$chartarea.AxisX.LabelStyle.Font = "Arial,24pt"
$chartarea.AxisX.LabelStyle.Format="HH:mm"
#$chartarea.AxisX.Minimum = $StartTime.TotalMinutes
#$chartarea.AxisX.Maximum = $EndTime.TotalMinutes
#$chartarea.AxisX.Minimum = 0*60 #17:30
#$chartarea.AxisX.Maximum = 24.0*60 #20:00
$chartarea.AxisY.LabelStyle.Font = "Arial,24pt"
$chartarea.AxisY.Minimum = 256
if ($SetExceedingToMaxCallTime)
{
$chartarea.AxisY.Maximum = [Math]::Pow([Math]::Round([Math]::Sqrt($MaxCallTimeToChart)+0.5,0),2)*1024
}
else
{
$chartarea.AxisY.Maximum = 131072
}
$chartarea.AxisY.Interval = 1
$chartarea.AxisY.MinorGrid.Enabled = $true
$chartarea.AxisY.IsLogarithmic=$true
$chartarea.AxisY.MinorGrid.LineColor = [System.drawing.color]::LightGray
$chart1.ChartAreas.Add($chartarea)
# legend
if ($ShowLegend)
{
write-host add event to scatter chart
$custjob = Register-ObjectEvent -InputObject $chart1 -EventName CustomizeLegend -Action $chart1_CustomizeLegend
write-host 'create legend scatter chart'
$legend = New-Object system.Windows.Forms.DataVisualization.Charting.Legend
$legend.name = "Legend1"
$chart1.Legends.Add($legend)
write-host 'format legend scatter chart'
$chart1.Legends["Legend1"].Font = "Arial,{0}pt" -f (6 * $GraphScale)
$chart1.Legends["Legend1"].Docking =[System.Windows.Forms.DataVisualization.Charting.Docking]::Right
#$chart1.Legends["Legend1"].LegendItems
}
# data series
#$chart1.Series["wGLN"].Legend = "Legend1"
#$chart1.Series["wGLN"].color = "#62B5CC"
#dev
$labelNum = 0
$series = @()
$pointsadded = 0
$DataArray | ForEach-Object {
if ($pointsadded % 100 -eq 0) { write-host ("Adding data Series [{0}] Points [{1}]" -f $series.Count,$pointsadded) Write-progress -status ("Adding data Series [{0}] Points [{1}]" -f $series.Count,$pointsadded) -activity "Preparing $ChartName" }
$seriesname = Invoke-Command $seriesSB -ArgumentList $_
if (!($series -contains $seriesname))
{
write-host 'create a series'
$theSeries = $chart1.Series.Add($seriesname)
$theSeries.ChartType = "Point"
$theSeries.BorderWidth = 2
$theSeries.IsVisibleInLegend = $true
$theSeries.chartarea = "ChartArea1"
$theSeries.MarkerSize = 6/[Math]::Sqrt([Math]::Sqrt([Math]::Max($DataArray.Count/1000,1)))*$GraphScale
$theSeries.BorderColor=$theSeries.Color
$theSeries.BorderWidth = 2
write-host 'add series'
$series += $seriesname
$theSeries.IsVisibleInLegend=$true
$theseries.Legend = "Legend1"
}
else
{
#series dictionary is case sensitive however IIS logs are not,
#use whereclause instead of dictionary lookup to ensure case insensitive match!
$theSeries = $chart1.Series | where {$_.Name -eq $seriesname}
}
if ($_['time-taken'] -gt 0)
{
if ($SetExceedingToMaxCallTime)
{
$theSeries.Points.addxy( [DateTime]($_["time"]) , [Math]::Min($MaxCallTimeToChart*1000,($_['time-taken']))) > $null;
}
else
{
$theSeries.Points.addxy( [DateTime]($_["time"]) , (($_['time-taken']))) > $null;
}
}
$pointsadded++
}#each dataarray
foreach ($item in $chart1.Legends["Legend1"].CustomItems) {$item.MarkerSize = 8}
#$chart1.Show()
write-host "save charte $chartname"
$filename = "$DestinationPath\$ChartName.png"
$chart1.SaveImage($filename,"png")
解决方案
我最初的想法是以下内容不正确:
$e.LegendItems[$i].MarkerSize=10
从我用我的 Google-foo 读到的一点点来看,你不能markersize
直接改变。您必须更改SeriesSymbolSize
. 我可能错了(我以前从未合作Datavisualization.Charting
过)
尝试更换:
for ($i = 0 ; $i -lt $e.LegendItems.Count ; $i++)
{
write-host processing $i
if ($e.LegendItems[$i] -eq $null)
{
write-host item is null
}
else
{
write-host item is not null
}
#update marker size
$e.LegendItems[$i].MarkerSize=10
}
和:
foreach($item in $e.LegendItems)
{
item.Cells(0).SeriesSymbolSize = 10
}
推荐阅读
- python - Python识别带引号和不带引号
- python - 您可以将其转换为嵌入吗?不和谐.py
- docusignapi - 如何与我们的 Web 应用程序集成?
- matlab - 在 MATLAB 中查找凸壳平面的方程
- angular - 如何在 COC neo vim 中设置 Coc-Angular lsp 扩展
- javascript - 控制台.log('\n'); 在 for of 循环内的 setTimeout 之后
- php - 我需要知道如何使用 laravel 中的资源控制器将数据从数据库检索到多个页面
- c++ - 如何将 C++20 约束的多个返回类型要求合并为一个返回类型要求?
- gitlab-ci - CypressError: `cy.visit()` 尝试加载失败: https://dev-eccc.env.xxxx.com/ 通过 Gitlab CI 作业
- python - 如何在 Pandas DataFrame 中将可变大小的基于字符串的列拆分为多列?