Announcement

Collapse

Looking for a User App or Add-On built by the NinjaTrader community?

Visit NinjaTrader EcoSystem and our free User App Share!

Have a question for the NinjaScript developer community? Open a new thread in our NinjaScript File Sharing Discussion Forum!
See more
See less

Partner 728x90

Collapse

Unhandled exception after changing color through user interface

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

    Unhandled exception after changing color through user interface

    I am occasionally getting an unhandled exception "The calling thread cannot access this object because a different thread owns it". The undhandled exception occurs after a custom brush was changed via the indicator dialogue box.

    The custom brush myCustomBrush is set and seriaized in the Properties section of the indicator as needed.The custom brush is then used for several plots, which I have done in State.Configure(), see code below

    Code:
    Plots[0].Brush = myCustomBrush.Clone();
    Plots[1].Brush = myCustomBrush.Clone();
    Plots[2].Brush = myCustomBrush.Clone();
    I have not frozen myCustomBrush, as I believe that State.Configure() runs on the UI thread, which would be the same thread as the one used for setting the properties. The plot brushes Plots[0].Brush, Plots[1].Brush, Plots[2].Brush are then accessed by a custom OnRender() section for the purpose of creating DX brushes.This does not seem to work correctly. Therfore I am asking you two questions:

    (1) Is it best practice to set those plot brushes in State.Configure, or should they be set in State.SetDefaults()?

    (2) Do I need to freeze the plot brushes as per code below?

    Code:
    Plots[0].Brush.Freeze(); 
    Plots[1].Brush.Freeze(); 
    Plots[2].Brush.Freeze();

    #2
    Hello Harry,

    Thanks for your questions.

    It is fine to set Plot brushes within the State.Configure method. Custom brushes will have to be frozen before they are accessed, which looks like the issue you are running into. Once the custom brush has been frozen, it can be used freely and assigned to the Plot Brushes.

    Code:
    if (State == State.SetDefaults)
    {
    	myBrush = new SolidColorBrush(Color.FromRgb(56, 120, 153));
    	myBrush.Freeze(); 
    }
    else if(State == State.Configure)
    {
    	Plots[0].Brush = myBrush;
    }
    Further reference on using custom brushes can be found here: https://ninjatrader.com/support/help...gcustombrushes

    I have also linked an indicator that creates some SharpDX brushes following best practices and adds a custom brush.

    Please let us know if we can be of additional help.
    Attached Files
    JimNinjaTrader Customer Service

    Comment


      #3
      Hello Jim,

      Thank you for your reply.

      It was my understanding that I only need to freeze brushes, if I wish to use them in a different thread.

      In your example, the brush is created in State == State.SetDefaults, and it is called in State == State.Configure. The brush is not used anymore afterwards. As State == State.SetDefaults and State == State.Configure are running on the same thread, why would I need to freeze the brush?

      I think that the problem occured when I tried to access Plots[0].Brush in OnRender(). Therefore my question was whether I need to freeze Plots[0].Brush.

      Comment


        #4
        Hello Harry,

        Freezing custom brushes after creation is recommended as a best practice to avoid multi threading issues. The best practice would be to freeze your custom brush after creation and before assigning it to Plots[0].Brush instead of freezing Plots[0].Brush. If you are certain that you are using these custom brushes on the UI thread and nowhere else, you can waive this practice.

        If you are creating a custom brush in State.Configure, it would exist on the UI thread and can also be accessed within OnRender(). Without full context of your code, I am not sure where the brushes are being accessed and where the issue is being thrown. It can be avoided by freezing the brush after creation, however.

        To demonstrate this discussion, I have attached a quick test where we create custom brushes in Sate.Configure and in State.DataLoaded and set Plots[0].Brush in OnRender(). The brush created in State.Configure does not get frozen, and this is OK since we are accessing it in OnRender() on the UI thread. If we change the Plots[0].Brush assignment to use the brush created in State.DataLoaded, the assignment will only work if we freeze that custom brush after it has been created.

        In the other example, cloning and freezing of brushes occurs in UpdateBrush() and SetOpacity(). The CustomBrush item accessible in the brush property combo boxes is frozen in the get field of that property.
        Attached Files
        JimNinjaTrader Customer Service

        Comment


          #5
          Jim,

          Thank you very much for your detailed examples which may also be of value to other users.

          I will change my habits to freeze all brushes now, regardless if it is needed or not. I believe that the issue will be fixed by freezing the brush. The text below only aims at understanding what has happened, not at fixing the issue.

          However, I am still confused what caused the occasional - non reproducible - error messages. This is all i did:

          (1) Set the brush in the properties section

          Code:
                  public System.Windows.Media.Brush MyCustomBrush
                  { 
                      get {return myCustomBrush;}
                      set {myCustomBrush = value;}
                  }
          
                  [Browsable(false)]
                  public string MyCustomBrushSerializable
                  {
                      get { return Serialize.BrushToString(myCustomBrush); }
                      set { myCustomBrush = Serialize.StringToBrush(value); }
                  }
          (2) Clone the brush in State.Configure() to use it with three plots.

          Code:
                 Plots[0].Brush = myCustomBrush.Clone();
                 Plots[1].Brush = myCustomBrush.Clone();
                 Plots[2].Brush = myCustomBrush.Clone();
          (3) Access the plot brushes in OnRender() as DX brushes, for example

          Code:
          RenderTarget.DrawLine(startPointDX, endPointDX, Plots[0].BrushDX, Plots[0].Width, Plots[0].StrokeStyle);
          I am not accessing myCustomBrush anywhere else, as it had just been created to use the same color for several plots. I did not freeze myCustomBrush, as I thought it would not be necessary. Where is my mistake?

          The exception may be occasionally thrown when the brush is changed via indicator dialogue box by typing the new color.

          Comment


            #6
            Jim,

            I know that I can be a pain .... but I have applied the HeikinAshiSmoothedCustomBrushTest indicator that you have attached in post #2 to a 1000 tick chart for ES.

            The indicator threw an exception and the chart panel could no longer be accessed. As all other windows were also frozen, I had to force down NinjaTrader via the task manager. This was the error message that was shown in both log and trace files.

            "Indicator 'HeikenAshiSmoothed': Error on calling 'OnRender' method on bar 2553: External component has thrown an exception."

            I was able to reproduce this behavior only once, although I have tried hard. It is a bit like my problem. Not easily reproducible. Sometimes causes crashing NinjaTrader. I use NinjaTrader 8.0.13.1 (64-bit).

            Update: The indicator throws an exception from time to time. Usually this does not lead to a freeze of NinjaTrader, but the indicator simply disappears from the chart, while other indicators are not affected. The HeikinAshiSmoothedCustomBrushTest definitely has a bug.
            Last edited by Harry; 05-22-2018, 12:53 PM.

            Comment


              #7
              Hello Harry,

              I've put that indicator through some extensive tests before modifying. (I like to open 6-8 charts with an indicator with custom rendering applied, disconnect and reconnect to the data provider and click on each chart to invoke RenderTarget changes when testing custom rendering.) I can't reproduce on my end and I could not encounter the same issues you were reporting with your logic.

              With your logic, we have a property for a user defined brush. This is different from a custom brush that is created in code with System.Windows.Media.Color.FromRgb(). In the attached test, I have 2 user defined brushes, one with a backing field as in your example, and another as an AutoProperty. I do not see issue using either context, and I do not see a context where freezing the brush would be necessary since the user defined brushes are not custom brushes created with NinjaScript.

              I understand that the issue may be hard to reproduce, but we should ask the questions:

              Is this issue seen in a clean environment where we can rule out all other factors? (Clean environments can be created by closing NinjaTrader, renaming the NinjaTrader folder in My Documents, uninstalling and then reinstalling. Please also remove/rename the NinjaTrader 8 folder in Program Files before reinstalling so other 3rd party plugins that have may have been installed to the Program Files folder can be isolated.)

              Is this reproducible on multiple PC's?

              If it can be reproduced, what data series factors are needed to create a chart that throws this issue?

              So we can help you move forward towards a resolution, could you provide some instruction and modifications to any of the attached code so we can reproduce the issue on our end?

              I don't mind issues being reported to look into. If there is something we can chase after, I am more than willing to invest the effort.
              Attached Files
              JimNinjaTrader Customer Service

              Comment


                #8
                Jim,

                Thank you very much for all your efforts.

                I believe that I have been running the indicators on a clean environment. However, I have not been testing them with a second PC. It is next to impossible to reproduce the behavior on purpose. I believe that it may have something to do with mouse events (clicking the chart repeatedly) or with a recompile that I did while the indicator was applied to the chart.

                In case that I am able to reproduce any of the issues, I will come back and report my findings.

                One last question: In the sample indicator you attached to your latest post, you are setting the plot brushes in State == State.DataLoaded. Why is this? I have always set them in State.Configure on the UI thread.

                Comment


                  #9
                  Hello Harry,

                  I chose State.DataLoaded just to demonstrate that threading/freezing should not be an issue. In post 4 we see where this is an issue when creating custom brushes with System.Windows.Media.Color.FromRgb() in State.DataLoaded vs. State.Configure. With user defined brushes like in post 7, we aren't hitting this issue.

                  If you come up with a scenario we can use to test, I'll be happy to give it a few tries. Feel free to send me a message at platformsupport[at]ninjatrader[dot]com and we can look into this and troubleshoot further as needed.
                  JimNinjaTrader Customer Service

                  Comment

                  Latest Posts

                  Collapse

                  Topics Statistics Last Post
                  Started by Aviram Y, Today, 05:29 AM
                  0 responses
                  2 views
                  0 likes
                  Last Post Aviram Y  
                  Started by quantismo, 04-17-2024, 05:13 PM
                  3 responses
                  25 views
                  0 likes
                  Last Post NinjaTrader_Gaby  
                  Started by ScottWalsh, 04-16-2024, 04:29 PM
                  7 responses
                  34 views
                  0 likes
                  Last Post NinjaTrader_Gaby  
                  Started by cls71, Today, 04:45 AM
                  0 responses
                  6 views
                  0 likes
                  Last Post cls71
                  by cls71
                   
                  Started by mjairg, 07-20-2023, 11:57 PM
                  3 responses
                  216 views
                  1 like
                  Last Post PaulMohn  
                  Working...
                  X