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

PropertyGrid Nested Properties Update Issue

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

    PropertyGrid Nested Properties Update Issue

    I have attached a demonstration AddOn to show the odd behaviour of a nested Property; i.e. a Property that is defined within the context of an ExpandableObjectConverter TypeConverter.

    The PropertyGrid uses only a clone of the source properties as its SelectedObject – it only changes the source properties when OK is clicked.

    The Property defined at the Top level of the properties class behaves as expected, i.e. the clone version of the properties is used for the change and the change is discarded if Cancel is clicked.

    The nested Property seems to be set in the “real” version of the properties immediately upon the change in the UI, despite the clone being used as the selected object.

    I would be most grateful for:
    • Advice on how to make the nested Property behave as expected; i.e. only change within the clone, not the real properties
    • Any improvements in how to refresh the UI after a Cancel – at the moment what I’m doing seems very clunky
    Many thanks.
    Attached Files
    Multi-Dimensional Managed Trading
    jeronymite
    NinjaTrader Ecosystem Vendor - Mizpah Software

    #2
    hello jeronymite,

    Thanks for the post.

    I took a quick look at the sample however it seems you are creating a property grid yourself here and working with that directly which is not something we can assist with. Do you still see the same happening if you use an indicator that has a public property with your ExpandableObjectConverter class? if so we may be able to provide that to development for review with the internal property grid, working outside of that context with the propertygrid control directly is not supported as we have no documentation for that to be used correctly.

    We generally suggest to use categories rather than the ExpandableObjectConverter as there are other limitations surrounding that such as no tooltips for properties but could include other issues as it is not a supported type converter.

    I look forward to being of further assistance.
    JesseNinjaTrader Customer Service

    Comment


      #3
      Originally posted by jeronymite View Post
      I have attached a demonstration AddOn to show the odd behaviour of a nested Property; i.e. a Property that is defined within the context of an ExpandableObjectConverter TypeConverter.

      The PropertyGrid uses only a clone of the source properties as its SelectedObject – it only changes the source properties when OK is clicked.

      The Property defined at the Top level of the properties class behaves as expected, i.e. the clone version of the properties is used for the change and the change is discarded if Cancel is clicked.

      The nested Property seems to be set in the “real” version of the properties immediately upon the change in the UI, despite the clone being used as the selected object.

      I would be most grateful for:
      • Advice on how to make the nested Property behave as expected; i.e. only change within the clone, not the real properties
      • Any improvements in how to refresh the UI after a Cancel – at the moment what I’m doing seems very clunky
      Many thanks.
      In "public class clsTestProperties : INotifyPropertyChanged, ICloneable", you may want to make your Clone() method a deep clone. MemberwiseClone() creates a shallow clone, so the properties in the clone, of any objects that are passed by reference, will be referencing the field in the original object. Any changes in the clone will be reflected in the original cloned object.

      Comment


        #4
        Thanks, koganam. Your insight is absolutely correct!

        DeepCopy (so-called) is indeed the issue. I have implemented a form of DeepCopy that uses XmlSerializer and works well enough. Unfortunately, XmlSerializer requires that the object cloned has an empty constructor and it only serializes public variables.

        I am experimenting with SOAP and Binary formatters which I hope will add greater flexibility.

        Thanks!
        Multi-Dimensional Managed Trading
        jeronymite
        NinjaTrader Ecosystem Vendor - Mizpah Software

        Comment


          #5
          Originally posted by jeronymite View Post
          Thanks, koganam. Your insight is absolutely correct!

          DeepCopy (so-called) is indeed the issue. I have implemented a form of DeepCopy that uses XmlSerializer and works well enough. Unfortunately, XmlSerializer requires that the object cloned has an empty constructor and it only serializes public variables.

          I am experimenting with SOAP and Binary formatters which I hope will add greater flexibility.

          Thanks!
          Have you tried instead, for deep-cloning, to simply create a new copy of the object by calling the constructor, then copying the field values from the original object into the clone? You can use any constructor, not necessarily a default empty one.
          Last edited by koganam; 08-20-2020, 03:19 PM.

          Comment


            #6
            Thanks for the suggestion, koganam.

            I had thought about that, but I'm actually trying to achieve a number of things in the process of understanding this whole matter. The cloning process is one use of the broader approach of how to make a copy of an object and do a store/restore cycle on it. One can do this in memory or file. Memory is good for cloning for live use. File is essential for persistent data between application invocations or for data transfer.

            Creating a copy using the constructor and then updating fields with variations of the data as need be is perfectly good, so long as the size of the object is not "excessive". But it does require bespoke code for each object type. A more generic approach could be used broadly with almost any object type, and in a more generically "atomic" manner.

            So far, I've implemented writers/readers for Xml, Binary and Soap. They can handle virtually any object of any size with notable exceptions related to scope of data in the object (public vs non-public), type of constructor (empty), serializable attributes, and implementation method (e.g. handling generic parameters). None is ideal.

            I have found Xml to be the most reliable, but also more limited (public scope required, etc). Binary works well with fewer limitations. Soap can work well too, but is more fragile and is not supported with generic parameters. Both Binary and Soap have challenges related to assembly information included in the resulting data output that may have to be overcome when reading.

            I have yet to leap into DataContract, although that seems to be frequently cited as flexible and robust.

            It's all rather daunting, I have to say. And time-consuming and frustrating. But that's programming generally, at times.

            Thanks again for insights and ideas!
            Multi-Dimensional Managed Trading
            jeronymite
            NinjaTrader Ecosystem Vendor - Mizpah Software

            Comment


              #7
              Originally posted by jeronymite View Post
              Thanks for the suggestion, koganam.

              I had thought about that, but I'm actually trying to achieve a number of things in the process of understanding this whole matter. The cloning process is one use of the broader approach of how to make a copy of an object and do a store/restore cycle on it. One can do this in memory or file. Memory is good for cloning for live use. File is essential for persistent data between application invocations or for data transfer.

              Creating a copy using the constructor and then updating fields with variations of the data as need be is perfectly good, so long as the size of the object is not "excessive". But it does require bespoke code for each object type. A more generic approach could be used broadly with almost any object type, and in a more generically "atomic" manner.

              So far, I've implemented writers/readers for Xml, Binary and Soap. They can handle virtually any object of any size with notable exceptions related to scope of data in the object (public vs non-public), type of constructor (empty), serializable attributes, and implementation method (e.g. handling generic parameters). None is ideal.

              I have found Xml to be the most reliable, but also more limited (public scope required, etc). Binary works well with fewer limitations. Soap can work well too, but is more fragile and is not supported with generic parameters. Both Binary and Soap have challenges related to assembly information included in the resulting data output that may have to be overcome when reading.

              I have yet to leap into DataContract, although that seems to be frequently cited as flexible and robust.

              It's all rather daunting, I have to say. And time-consuming and frustrating. But that's programming generally, at times.

              Thanks again for insights and ideas!
              I see what you are saying, but yes, being such an anal-retentive idiot control freak, I have a tendency to use bespoke methods, so that I know exactly what is going on. I have written though a deep clone extension method for when I am getting just too lazy and need quick service. It uses a binary stream formatter, so really can be used for just about anything, as long as all the members of the object are capable of being serialized. That means of course, bespoke code for any custom objects in the object to be cloned, but there is really no getting around that. We have to write serializers for custom classes anyway, if we want any kind of persistence.

              Maybe you have already tried something like this?

              Code:
              using System;
              using System.IO;
              using System.Runtime.Serialization.Formatters.Binary;
              
              public static class DeepCloneExtension
              {
                  //Class to be cloned MUST be decorated with [Serializable] attribute.
                  public static T DeepCloneSerializedObject<T>(this T toClone)
                      {
                          using (var stream = new MemoryStream())
                              {
                                  var formatter = new BinaryFormatter();
                                  formatter.Serialize(stream, toClone);
                                  stream.Seek(0, SeekOrigin.Begin);
                                  return (T)formatter.Deserialize(stream);
                              }
                      }
              
                  public static T CloneObject < T > (this object source)
                      {
                          T result = Activator.CreateInstance < T > ();
                          //// **** make assignments
                          return result;
                      }
              }
              Last edited by koganam; 08-21-2020, 09:17 PM.

              Comment


                #8
                Thanks, koganam. I have a slight variation on that theme (with apologies for the idiosyncratic naming convention) using XmlSerialization:

                Code:
                using System;
                using System.IO;
                using System.Xml.Serialization;
                
                public static void DeepCopyTo<T>(this T pOriginal,[INDENT=5]      ref T pXerox)[/INDENT]
                 
                 {[INDENT]using (var ms = new MemoryStream())
                {[/INDENT][INDENT=2]var cereal = new XmlSerializer(typeof(T));
                cereal.Serialize(ms,pOriginal);
                ms.Position = 0;
                pXerox = (T)cereal.Deserialize(ms);[/INDENT][INDENT]}[/INDENT]
                 
                 }
                I also have a Binary version, but I use that more for persistence. I like your approach with the Activator. I'll explore that a little further.

                Thanks again.
                Last edited by jeronymite; 08-22-2020, 04:31 AM.
                Multi-Dimensional Managed Trading
                jeronymite
                NinjaTrader Ecosystem Vendor - Mizpah Software

                Comment

                Latest Posts

                Collapse

                Topics Statistics Last Post
                Started by DJ888, 04-16-2024, 06:09 PM
                6 responses
                18 views
                0 likes
                Last Post DJ888
                by DJ888
                 
                Started by Jon17, Today, 04:33 PM
                0 responses
                1 view
                0 likes
                Last Post Jon17
                by Jon17
                 
                Started by Javierw.ok, Today, 04:12 PM
                0 responses
                6 views
                0 likes
                Last Post Javierw.ok  
                Started by timmbbo, Today, 08:59 AM
                2 responses
                10 views
                0 likes
                Last Post bltdavid  
                Started by alifarahani, Today, 09:40 AM
                6 responses
                41 views
                0 likes
                Last Post alifarahani  
                Working...
                X