Dear NinjaTrader Support,
I’m encountering a persistent DirectX error when switching between workspaces, even when following documented best practices for SharpDX resource management in NinjaScript. This happens even in a minimal indicator that draws a single line using a correctly managed SharpDX brush and implements OnRenderTargetChanged() properly.
Steps To Reproduce
- Add the attached
SimpleDxLineTestindicator to any chart. - Switch to a different workspace (leaving the current chart open but no longer visible).
- Observe the NinjaScript Output Log or Control Center > Log tab.
You’ll see the following DirectX error immediately upon switching away:
A direct X error has occurred while rendering the chart: HRESULT: [0x88990015]
Module: [SharpDX.Direct2D1]
ApiCode: [D2DERR_WRONG_RESOURCE_DOMAIN/WrongResourceDomain]
Message: The resource was realized on the wrong render target.
Observations
- No calls to
OnRender()orOnRenderTargetChanged()** are made at the moment of workspace switch (verified via print logs). - Error occurs only when switching away from the workspace.
- When switching back,
OnRender()andOnRenderTargetChanged()are called, and rendering resumes without any error. RenderTarget.IsDisposedremainsfalsethroughout.
Implementation Notes
The indicator:
- Uses SharpDX properly: brushes are disposed and recreated in
OnRenderTargetChanged(). - Never accesses
RenderTargetoutsideOnRender()orOnRenderTargetChanged(). - Avoids calling
ToDxBrush()at runtime. - All rendering is guarded by null checks and
IsDisposedchecks.
Expected Behavior
If the chart is no longer visible (due to workspace switch), OnRender() should not be invoked — and if it is, SharpDX resources tied to a different render target shouldn’t cause a crash if we’re not actively drawing. Or OnRenderTargetChanged() should be invoked when switching away and back to a workspace so that it can handle the dispose and create of SharpDx resources to prevent the run time error
I’ve attached the SimpleDxLineTest.cs file that demonstrates the issue in isolation.
#region Using declarations
using System;
using System.Windows.Media;
using SharpDX;
using SharpDX.Direct2D1;
using NinjaTrader.Cbi;
using NinjaTrader.Gui.Tools;
using NinjaTrader.NinjaScript;
using NinjaTrader.Data;
using NinjaTrader.Gui.Chart;
using NinjaTrader.NinjaScript.Strategies;
using NinjaTrader.NinjaScript.Indicators;
using Media = System.Windows.Media;
#endregion
namespace NinjaTrader.NinjaScript.Indicators
{
public class SimpleDxLineTest : Indicator
{
private SharpDX.Direct2D1.Brush dxBrush;
private StrokeStyle strokeStyle;
protected override void OnStateChange()
{
if (State == State.SetDefaults)
{
Description = "Draws a DX line at Close[0]";
Name = "SimpleDxLineTest";
IsOverlay = true;
Calculate = Calculate.OnEachTick;
IsSuspendedWhileInactive = true;
}
else if (State == State.Terminated)
{
strokeStyle?.Dispose();
dxBrush?.Dispose();
}
}
public override void OnRenderTargetChanged()
{
Print($">>> [OnRenderTargetChanged] called at {DateTime.Now:HH:mm:ss.fff}");
// Only create strokeStyle once
if (strokeStyle == null)
{
strokeStyle = new StrokeStyle(Core.Globals.D2DFactory,
new StrokeStyleProperties { DashStyle = SharpDX.Direct2D1.DashStyle.Solid });
}
dxBrush?.Dispose();
dxBrush = new SharpDX.Direct2D1.SolidColorBrush(RenderTarget, SharpDX.Color.DodgerBlue);
}
protected override void OnRender(ChartControl chartControl, ChartScale chartScale)
{
Print($">>> [OnRender] called at {DateTime.Now:HH:mm:ss.fff}");
if (ChartBars == null || chartScale == null || RenderTarget == null)
return;
// Draw horizontal line in the middle of chart panel
float y = ChartPanel.H / 2f;
RenderTarget.DrawLine(
new Vector2(0, y),
new Vector2(ChartPanel.W, y),
dxBrush,
2f,
strokeStyle
);
}
}
}
Please let me know if there is a lifecycle-safe workaround or recommended approach to handle workspace switches cleanly without triggering this error. I’m happy to assist with any additional diagnostics.