Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Chart Trader Buttons on 2 Panels

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Chart Trader Buttons on 2 Panels

    Hi, my chart window has 2 panels, each showing the chart of a different instrument. When I open up the chart trader, they share the same chart trader.

    I have developed an indicator that draws a set of buttons on the chart trader and I load one indicator onto each panel.

    Sometimes, the sets of buttons can draw and stack properly on top each other.

    Most of the times, the buttons do not draw for one or both indicators and the log shows the error "This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread."

    When this happens, I open up the properties of the indicator and discover that the Input Series under Data Series becomes "Close" instead of the instrument name.

    To get both sets of buttons to show correctly, I need to press F5 many times to keep refreshing the chart until the error disappears.


    I have tried adding delay to one of the indicators, so they do not load at the same time:

    PHP Code:
               else if (State == State.Historical)
                {
                    if (ChartControl != null)
                    {
                        ChartControl.Dispatcher.InvokeAsync(() =>
                        {
                            Thread.Sleep(1000);  // Added this line           
                            CreateWPFControls();
                        });
                    }
                }
    ​ 
    

    However, the above do not seem to resolve the issue.

    May I ask what is causing the error and what can I do to resolve it?

    Thank you very much for your assistance.

    #2
    Hello Rainmakersg,

    Don't call Sleep() or Wait() in a NinjaScript as this will freeze the entire instrument thread and possibly the entire platform.

    You will need logic that adds rows to the ChartTrader grid or first child of the ChartTrader grid, then remove the row containing the bottoms only.

    See the SampleWPFModifications indicator in all regions with the name 'Use case #5: Custom chart trader buttons'.

    The specific row related code is on lines 732 - 742 and 936 - 948.
    Chelsea B.NinjaTrader Customer Service

    Comment


      #3
      Hi Chelsea, thanks fore your reply.

      Are you advising that I should make sure the 2 sets of buttons do not overlap visually, such that the higher set of buttons have some bottom spacings removed and the lower set is stuffed with extra spacing? If so, I have already done these and made sure the 2 sets of buttons do not overlap.

      If it is just a visual thing, can you advise why I am getting the error "This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread." and why refreshing by F5 many times can resolve the problem?

      Comment


        #4
        Hello Rainmakersg,

        It could be that a ChartControl.Dispatcher.InvokeAsync() was not used to add / remove / modify the controls, or could be another issue.

        The reference sample I've provided a link to does not exhibit this behavior when added to multiple panels and would be a good starting point.
        Chelsea B.NinjaTrader Customer Service

        Comment


          #5
          Hi Chelsea,

          Thanks for your reply.

          This is what I have done: I loaded the SampleWPFModifications indicator you provided into the instrument in panel 1 and did the same for the instrument in panel 2. So now the buttons stack in the chart trader.

          I then refresh the chart by pressing F5. Sometimes, the button meant for panel 1 appears at the bottom stack. This happens 3-7 times out of 10 refreshes. I did a series of 5 sets of 10 refreshes and the average results are similar.

          Under each indicators' property, even when I assign the panel to the panel number instead of using "Same as input series", I still get the same results.

          Is there way to make sure that the button meant for panel 1 always appears on the top of the stack in chart trader?

          Comment


            #6
            Hello Rainmakersg,

            To confirm, you are getting the 'This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread' error when using the SampleWPFModifications reference sample from the help guide?

            Unfortunately, its kind of a race when multiple indicators are loading on which adds it's buttons first. Typically, the first to load will have it's buttons on top.
            Chelsea B.NinjaTrader Customer Service

            Comment


              #7
              Hi Chelsea,

              Yes I am no longer getting any error message using your sample indicator. I have also extracted the relevant code from your sample indicator and added more buttons and I also no longer get the error message. Thank you very much for that.

              Is there any way to delay the loading of the panel 2 indicator or the rendering of the buttons within the indicator, so that its buttons appear at the bottom stack in chart trader?



              Comment


                #8
                Hello Rainmakersg,

                If two indicators are making wpf modifications at the same time and adding rows to the same grid in the same way, there is no guarantee which will be first.

                You could choose to make two versions of the indicators, one that adds a row as the first row, and one that adds a row as the last row.
                Chelsea B.NinjaTrader Customer Service

                Comment


                  #9
                  Hi Chelsea,

                  That doesn't seem to work. Seems like the best way is to delay the loading of the indicator in panel 2.

                  As you mentioned, Sleep() or Wait() is going to cause problems. I found this timer logic from the NT Best Practices guide (https://ninjatrader.com/support/help...ractices.htm):

                  PHP Code:
                  protected override void OnBarUpdate()
                  {
                    if (IsFirstTickOfBar && State == State.Realtime)
                    {
                      // Instead of Thread.Sleep for, create a timer that runs at the desired interval
                      System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer {Interval = 5000};
                   
                      // queue the "after" logic to run when the timer elapses
                      timer.Tick += delegate
                      {
                          timer.Stop(); // make sure to stop the timer to only fire ones (if desired)
                          Print("Run some logic after: " + DateTime.Now);
                          timer.Dispose(); // make sure to dispose of the timer
                      };
                   
                      Print("Run some logic before: " + DateTime.Now);
                   
                      timer.Start(); // start the timer immediately following the "before" logic
                    }
                  }​ 
                  

                  It is possible to run a similar timer logic in State.Historical but before the InvokeAsync and not cause any problems:
                  PHP Code:
                  
                  
                              else if (State == State.Historical)
                              {
                                  if (ChartControl != null)
                                  {
                                      // <run similar timer logic here>
                  
                                      ChartControl.Dispatcher.InvokeAsync((System.Action)(() =>
                                      {
                                          LoadBrushesFromSkin();
                  
                                          CreateWPFControls();
                                      }));
                                  }
                              }&#8203; 
                  

                  Comment


                    #10
                    Hello Rainmakersg,

                    "That doesn't seem to work."

                    To confirm you have two copies of the indicator with different names? One is adding a row using RowDefinitions.Insert and the other using RowDefinitions.Add()?

                    Using a timer would be fine, enabling the timer from State.Historical would be fine.

                    The Dispatcher.InvokeAsync() and tasks would be done from the timer Tick event handler.
                    Chelsea B.NinjaTrader Customer Service

                    Comment

                    Latest Posts

                    Collapse

                    Topics Statistics Last Post
                    Started by Geovanny Suaza, 02-11-2026, 06:32 PM
                    0 responses
                    597 views
                    0 likes
                    Last Post Geovanny Suaza  
                    Started by Geovanny Suaza, 02-11-2026, 05:51 PM
                    0 responses
                    343 views
                    1 like
                    Last Post Geovanny Suaza  
                    Started by Mindset, 02-09-2026, 11:44 AM
                    0 responses
                    103 views
                    0 likes
                    Last Post Mindset
                    by Mindset
                     
                    Started by Geovanny Suaza, 02-02-2026, 12:30 PM
                    0 responses
                    556 views
                    1 like
                    Last Post Geovanny Suaza  
                    Started by RFrosty, 01-28-2026, 06:49 PM
                    0 responses
                    555 views
                    1 like
                    Last Post RFrosty
                    by RFrosty
                     
                    Working...
                    X