String.length of instance/type parameter.

String.length of instance/type parameter.

mohd.fadel
Enthusiast Enthusiast
2,878 Views
20 Replies
Message 1 of 21

String.length of instance/type parameter.

mohd.fadel
Enthusiast
Enthusiast

Hello everyone,

 

I'm using Revit and Revit sdk 2013.

 

There is something weird happening, and i couldn't find anything related to my problem. I'm trying to find the length of a an instance parameter. Everything works perfectly when i retrieve the parameter.

 

Here is my code:

 

Document doc = e.GetDocument();

            ICollection<ElementId> addedElem = e.GetAddedElementIds();
            foreach (ElementId id in addedElem)
            {
                Element elem = doc.GetElement(id);
                ParameterSet parameters = elem.Parameters;
                foreach (Parameter param in parameters)
                {
                    if (param.Definition.Name == "Test Parameter")
                    {

                         if (param.AsString() != "")
                         {
                             paramString = param.AsString();
                             int paramLength = paramString.Length;
                             System.Windows.Forms.MessageBox.Show(paramLength.ToString());

                         }

                    }

             }

 

 

Here's my problem, when i enter a value in my parameter that has a length greater than 10 (ex. "Hello by the way" 16 characters). The length is  displayed in a message box (16). However, if i enter a value less than 10 (ex. "Hello" 5 characters) Not even an empty box is displayed. Nothing is happening. It's like if the length of the string is less than 10 characters, it is not being recognized at all.

 

Anyone faced such a problem?

 

Regards.

 

M. Fadel

 

0 Likes
Accepted solutions (1)
2,879 Views
20 Replies
Replies (20)
Message 2 of 21

augusto.goncalves
Alumni
Alumni

The comparison that you're using is a little strange...

if (param.AsString() != "")

What if the string is empty spaces... or many others.

if (!String.IsNullOrWhiteSpace(param.AsString()))

Can you try it? Have you debugged your code?

Regards,



Augusto Goncalves
Twitter @augustomaia
Autodesk Developer Network
0 Likes
Message 3 of 21

mohd.fadel
Enthusiast
Enthusiast

Hello Augusto,

 

Thank you for your reply, and thank you for your solution regarding comparing to an empty field.

 

I tried it, still the same problem. I tried tracing the problem (didn't actually debug) but i believe it's an issue with the DocumentChangedEventArgs class or in the Autodesk.Revit.DB.Events namespace as whole.

 

I concluded that because the same logic works perfectly in a normal plug-in (i.e independent of the Events namespace). The plug-in reads the value, and length of the value "Hello" (value less than 10 characters). I don't know if this is a bug, but that's where i am now.

0 Likes
Message 4 of 21

augusto.goncalves
Alumni
Alumni
I would suggest you debug the code and check the value that is being returned on the parameter... you just mention the length, but what about the actual value?
Regards,



Augusto Goncalves
Twitter @augustomaia
Autodesk Developer Network
0 Likes
Message 5 of 21

mohd.fadel
Enthusiast
Enthusiast

Hello again Augusto,

 

I'm sorry for the late reply! We had the holidays here, and after that i was very busy i couldn't work on my project. I'm trying to debug my code. But i'm facing many issues. First, I had all buttons grayed out in Revit when  i started debugging my program.

 

I followed this fix : [http://blogs.msdn.com/b/visualstudioalm/archive/2013/10/16/switching-to-managed-compatibility-mode-i... and the buttons and extensions are now working.

 

But now, the debugger is not stopping at breakpoints. So basically i'm still not able to debug my program!

 

Anyways, you still don't believe it's an sdk issue/bug?

 

M. Fadel

0 Likes
Message 6 of 21

mohd.fadel
Enthusiast
Enthusiast

Augusto,

 

I was able to get the values at breakpoints when the value of the parameter is larger than 10 characters. The debugger is pausing only when the parameter is greater than 10 characters. This means i'm right back from where i started! Very weird..

0 Likes
Message 7 of 21

mohd.fadel
Enthusiast
Enthusiast

Still there Augusto?

0 Likes
Message 8 of 21

augusto.goncalves
Alumni
Alumni
Sorry, I remember replying to this... got confused somehow 🙂

What's bugging me the most is "the debugger only pause when >10"

Aren't you able to set the breakpoint earlier?

I don't see a reason for this code to fail due Revit API, but only if it's missing a step (like comparison or values on the .rtf)
Regards,



Augusto Goncalves
Twitter @augustomaia
Autodesk Developer Network
0 Likes
Message 9 of 21

mohd.fadel
Enthusiast
Enthusiast

No worries!

 

I can set breakpoints earlier. Even in the for loop!

 

However, if it's less than 10, "param.AsString()" is not recognized anymore! The debugger, as well as the program, are not recognizing the value inside. I don't think there's a comparison issue. I only have 2 conditions:

 

foreach (Parameter param in parameters)
                {
                    if (param.Definition.Name == "Test Parameter")
                    {
                        switch (param.StorageType)
                        {
                            case Autodesk.Revit.DB.StorageType.String:
                                if (!String.IsNullOrWhiteSpace(param.AsString()))
                                {
                                    dd = param.AsString().ToString().Substring(0, 2);
                                    -----;
   ------------->               paramString = param.AsString();                <--------------

                                    -----;

                                }

                            ----;

                         }

                     }

                 }

 

And values aren't the issue either. Like i said I tried 2 examples:

 

1st: Hello by the way!

2nd: Hello.

 

The first is working, the second is not!

0 Likes
Message 10 of 21

Revitalizer
Advisor
Advisor

Hi,

 

may it be that is it a matter of timing since Revit API is just a C# wrapper around native C++ Revit classes ?

Each time we read an Element's property or method, there is some additional working under the hood.

You call param.AsString() several times, so may it be that the last call is "choked" anyway ?

 

What about calling param.AsString() just one time, then storing the value in a string variable and using this one for comparison ?

 

Just an idea.

 

 

Revitalizer




Rudolf Honke
Software Developer
Mensch und Maschine





Message 11 of 21

mohd.fadel
Enthusiast
Enthusiast

Revitalizer!

 

Strangely it worked!!

 

Although i still don't understand why!? Whatever additional work is going on, what's this condition that's keeping it from reading values less than 10 characters?!

 

Anyways, I really appreciate your help!!

 

And thank you Augusto!

 

Regards.

0 Likes
Message 12 of 21

Revitalizer
Advisor
Advisor

Hi mohd.fadel,

 

hehe, seems that I've developed a special feeling for problems, over the years.

 

 

Best regards,

have a nice weekend,

 

Revitalizer

 




Rudolf Honke
Software Developer
Mensch und Maschine





0 Likes
Message 13 of 21

mohd.fadel
Enthusiast
Enthusiast

Hahaha!

 

Seems so.. Thanks again!

0 Likes
Message 14 of 21

arnostlobel
Alumni
Alumni

Hmm, interesting. I kind of doubt there is a timing issue "under the hood", although it is possible something gets screwed up when crossing the boundary between the managed and native code. I have see issues there before, usually stemming from rather strong optimization made by the garbage collector. I would be genuinely surprised if there was any string-stripping done on the Revit side.

 

I's like to look more into it to rule out any possibly serious bug we could fix (if we find it). Mhd.fadel, do you experience this behavior with any string parameter or only those you define yourself? Can you share mode details about the concrete parameters? I'l like to try to reproduce it. Thanks.

Arnošt Löbel
0 Likes
Message 15 of 21

mohd.fadel
Enthusiast
Enthusiast

Hello Arnošt,

 

Forgive me for not reopening the thread before. Calling param.AsString() several times wasn't the issue indeed!! It was an unfortunate coincidence that led me to believe that Revitalizer's post was the solution. However, it was something else...

 

Again my code was:

 

foreach (Parameter param in parameters)
                {
                    if (param.Definition.Name == "Test Parameter")
                    {
                        switch (param.StorageType)
                        {
                            case Autodesk.Revit.DB.StorageType.String:
                                if (!String.IsNullOrWhiteSpace(param.AsString()))
                                {
                                    dd = param.AsString().ToString().Substring(0, 2);
         ---------->             mm = param.AsString().ToString().Substring(3, 2);
         ---------->             yyyy = param.AsString().ToString().Substring(6, 4);

                                    paramString = param.AsString();            

                                    -----;

                                }

                            ----;

                         }

                     }

                 }

 

 

As you can see, i added 2 rows from my original code (the calculated month and year variables). Appartently, and again by coincidence, i put the 3 variables (dd,mm,yyyy) just after "paramString = param.AsString();" in my supposedly correct solution.

 

So my code became:

 

 

                    Element elem = doc.GetElement(id);
                    ParameterSet parameters = elem.Parameters;
                    Parameter param = elem.get_Parameter("Test Parameter");
                        if (!String.IsNullOrWhiteSpace(param.AsString()))
                        {

                            paramString = param.AsString();

 

                            dd = param.AsString().ToString().Substring(0, 2);
                            mm = param.AsString().ToString().Substring(3, 2);
                            yyyy = param.AsString().ToString().Substring(6, 4);           

                            -----;

                        }

 

And this worked!

 

But afterwards, i noticed that extracting the substrings from the original parameter was causing the problem! Specifically, if i put "paramString = param.AsString();" after mm variable!!!!! If i put it after dd it works fine!! Anywhere after mm and my original issue occurs!!!! (less than 10 characters parameters are not recognized).

 

And to answer your question, yes i'm experiencing this behavior in all parameters (not only user-defined).

 

p.s I'm marking this question as not answered again.

 

 

Regards,

 

M. Fadel

0 Likes
Message 16 of 21

Revitalizer
Advisor
Advisor

Hi mohd.fadel,

 

you say:

"But afterwards, i noticed that extracting the substrings from the original parameter was causing the problem!"

 

 

So, using my initial suggestion would not solve any underlying cause of the problem,

but could be used as a workaround to make your function run properly.

 

 

Revitalizer




Rudolf Honke
Software Developer
Mensch und Maschine





0 Likes
Message 17 of 21

mohd.fadel
Enthusiast
Enthusiast

Hello Revitalizer,

 

Actually, no.. Like i said turns out it was a coincidence (me changing the position of my variables in the code)!

 

And to make sure, i just tried it with my original code.. With the second loop.. And i omitted the variables (mm, yyyy).

 

It worked just fine!

 

 

M.Fadel

0 Likes
Message 18 of 21

arnostlobel
Alumni
Alumni

M.Fadel,

 

I have finally! got into looking into the problem you reported. That's the good news! Unfortunately, there is bad new news too, and it is that I am unable to reproduce the behavior you described. You mentioned that you could experience the bug using any string parameter. So I add a Comments to a single wall and got onto testing.

 

These are the steps I took:

  1. Create a simple wall element
  2. Set its Comments parameter to 123ABC789
  3.  Write a macro that gets the value of the parameter three times and does something with it
  4. The macro works as I would expect it to - I am not getting any empty strings.

Here's the code of the macro:

public void GetStringParameter()
{
   UIDocument uidoc = this.ActiveUIDocument;
   if (uidoc.Selection == null)
   {
      TaskDialog.Show("Info", "Select an element.");
      return;
   }
   
   ICollection<ElementId> elemIds = uidoc.Selection.GetElementIds();
   if (elemIds.Count != 1)
   {
      TaskDialog.Show("Info", "Select an element.");
      return;
   }
   
   ElementId elemId = elemIds.First();
   Element elem = uidoc.Document.GetElement(elemId);
   if (elem == null)
   {
      TaskDialog.Show("Error", "Could not get element");
      return;
   }
   
   Parameter comments = elem.get_Parameter(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS);
   if (comments == null)
   {
      TaskDialog.Show("Info", "Parameter \"Comments\" not found");
      return;
   }
   
   string svalue = comments.AsString();
   if (string.IsNullOrEmpty(svalue))
   {
      TaskDialog.Show("Info", "No comments!");
      return;
   }
   
   int halflen = svalue.Length / 2;
   string spart1 = comments.AsString().Substring(0, halflen);
   string spart2 = comments.AsString().Substring(halflen, (svalue.Length - halflen));
   
   string message = string.Format("String \"{0}\" consist of \"{1}\" and \"{2}\" halfs.", svalue, spart1, spart2);
   TaskDialog.Show("Resut", message);
}

 

As you can see, I do a very similar operation with the string like what you said you did. For each string I evaluate the parameter's string value independently and do something with it. And it works. For the Comment I entered I get two parts: 123A and BC789.

 

So, could it is a parameter dependent, after all?

I am testing it in 2016, but I would not expect any behavior in 2015.

 

Arnošt Löbel
0 Likes
Message 19 of 21

mohd.fadel
Enthusiast
Enthusiast

Hello again Arnošt,

 

I'm sorry for the late reply. I couldn't reply earlier. I tried your code too, it worked perfectly! I tried mine:

 

 

if (uidoc.Selection == null)
        {
            TaskDialog.Show("Info", "Select an element.");
            return Result.Succeeded;
        }
        
        ICollection<ElementId> elemIds = uidoc.Selection.GetElementIds();
        if (elemIds.Count != 1)
        {
            TaskDialog.Show("Info", "Select an element.");
            return Result.Succeeded;
        }
        
        ElementId elemId = elemIds.First();
        Element elem = uidoc.Document.GetElement(elemId);
        if (elem == null)
        {
            TaskDialog.Show("Error", "Could not get element");
            return Result.Succeeded;
        }

        //Parameter comments = elem.get_Parameter("Executed Date");
        Parameter comments = elem.get_Parameter(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS);
        
        if (comments == null)
        {
            TaskDialog.Show("Info", "Parameter \"Comments\" not found");
            return Result.Succeeded;
        }

        string svalue = comments.AsString();
        if (string.IsNullOrEmpty(svalue))
        {
            TaskDialog.Show("Info", "No comments!");
            return Result.Succeeded;
        }

        
        
        string dd;
        string mm;
        string yyyy;
        string paramString;
        int paramLength;


        dd = comments.AsString().ToString().Substring(0, 2);
        mm = comments.AsString().ToString().Substring(3, 2);
        yyyy = comments.AsString().ToString().Substring(6, 4);
        paramString = comments.AsString();
        paramLength = paramString.Length;
        System.Windows.Forms.MessageBox.Show(paramLength.ToString());

 

it didn't work! Although it has the same use of Substring!

 

As you can see, i tried 2 scenarios:

 

//Parameter comments = elem.get_Parameter("Executed Date");
Parameter comments = elem.get_Parameter(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS);

 

I tried your choice (using the Comments paramter). I thought i'll double check now that i'm not using the EventHandler. Same issue!! Only now, an error is occured when trying to enter values less than 10 characters:

 

Revit Error.png

 

 

at System.String.InternalSubStringWithChecks(Int32 startIndex, Int32 length, Boolean fAlwaysCopy).

Interesting! But i don't get it. Any ideas?

 

M. Fadel

0 Likes
Message 20 of 21

arnostlobel
Alumni
Alumni
Accepted solution

Well, naturally, I would expect to get that exception from your code for any string that is shorter than 10 characters. Since you unconditionally call the following:

yyyy = comments.AsString().ToString().Substring(6, 4);

It will always fail for strings shorter than 10 characters, because you are explicitly referencing characters from 6 to 9 (0-based index).

Are you now saying that except for this error (which requires a fix on your side) the parameter-value getting code works?

Arnošt Löbel