There has to be a better way...



  • currentControl is from a System.Web.UI.ControlCollection, so it is cast as a "Control". There has to be a better way to figure out what the actual subclass is.

     Current code:

    if (foundControl != null)
                    {
                        Type controlType = currentControl.GetType();                  
                       
                        if (controlType == typeof(Label))
                        {                       
                            Label control = (Label)currentControl;
                            control.Text = foundControl[_displayLabelColumn].ToString();
                        }
                        else if (controlType == typeof(Literal))
                        {
                            Literal control = (Literal)currentControl;
                            control.Text = foundControl[_displayLabelColumn].ToString();
                        }
                        else if (controlType == typeof(LinkButton))
                        {
                            LinkButton control = (LinkButton)currentControl;
                            control.Text = foundControl[_displayLabelColumn].ToString();
                        }
                       
                    }

     Repeat for every control that has a text property.



  •  Of course there's a better way.  I'll pseudocode it.

    1)  Generate random string of characters s.

    2)  if s = type goto 4

    3)  goto 1

    4) ??? 

    5)  Profit!



  • @belgariontheking said:

    Filed under: FUCKING HELL WHY DOES IT DELETE TWO CHARACTERS WHEN I HIT BACKSPACE ONCE?

    So it's not just me. I brought up a bunch of tag flaws in another sidebar post, and this was one of them. I'm gonna use that tag now.



  • @AbbydonKrafts said:

    @belgariontheking said:
    Filed under: FUCKING HELL WHY DOES IT DELETE TWO CHARACTERS WHEN I HIT BACKSPACE ONCE?

    So it's not just me. I brought up a bunch of tag flaws in another sidebar post, and this was one of them. I'm gonna use that tag now.

     

    Why the fuck doesn't it do that for me?



  • @dhromed said:

    Why the fuck doesn't it do that for me?
     

    Because you are not special enough.



  • @MasterPlanSoftware said:

    Because you are not special enough.

    :'( 



  • @belgariontheking said:

     Of course there's a better way.  I'll pseudocode it.

    1)  Generate random string of characters s.

    2)  if s = type goto 4

    3)  goto 1

    4) ??? 

    5)  Profit!

     

    Hey MasterPlanSoftware, whats step 4?


  • Considered Harmful

    I was dealing with this same issue. I made a simple class that is used like so:

    string strValue = new ValueControl( myControl ).Value;

    The class figures out if it's using Text, Checked, or SelectedValue based on the kind of control. Then I was able to write a loop for all controls in a form to collect all the values, without having to do any special-cases.

    Edit: Yes, I know, a function could have done the same. The class actually did a few more things than that, though.



  • @joe.edwards@imaginuity.com said:

    I was dealing with this same issue. I made a simple class that is used like so:

    string strValue = new ValueControl( myControl ).Value;

    The class figures out if it's using Text, Checked, or SelectedValue based on the kind of control. Then I was able to write a loop for all controls in a form to collect all the values, without having to do any special-cases.

    Edit: Yes, I know, a function could have done the same. The class actually did a few more things than that, though.

     

     Thats kind of backwards from what I need. I'm setting the text property, not retrieving it.

    This code is for this stupid localization system. Basicly, translators can use a tool to translate all the pages, which stores all text in a couple of database tables (mapping PageID and ControlID). Then when the page is rendered, all of the text gets swapped out with the proper localization.

     I fought long and hard for a different solution, but this is what we have to build. I did build in cacheing and defaulting to english without running the sproc, so it will only be a slow site for our global customers.



  •  @Jonathan Holland said:

    if (foundControl != null)
                    {
                        Type controlType = currentControl.GetType();                  
                       
                        if (controlType == typeof(Label))
                        {                       

    This kind of crud is all over the UI for a tool I do some maintenance on.  What's worse is that the types are most often types the original author wrote together, and gave each and every one a non-virtual copy of the same property.

     



  • Perhaps I'm reading the docs wrong, but doesn't System.Web.UI.WebControls.Label inherit from System.Windows.Forms.Label to get its Text member, which is then inherited from System.Windows.Forms.Control.  So... can't you just cast it as a System.Windows.Forms.Control and use the Text property?

     

    e.g.

    System.Windows.Forms.Control control = currentControl as System.Windows.Forms.Control;

    if(control!=null)

        control.Text = foundControl[_displayLabelColumn].ToString();

     

     



  • @Morbii said:

    Perhaps I'm reading the docs wrong, but doesn't System.Web.UI.WebControls.Label inherit from System.Windows.Forms.Label to get its Text member, which is then inherited from System.Windows.Forms.Control.  So... can't you just cast it as a System.Windows.Forms.Control and use the Text property?

     

    e.g.

    System.Windows.Forms.Control control = currentControl as System.Windows.Forms.Control;

    if(control!=null)

        control.Text = foundControl[_displayLabelColumn].ToString();

     

     

     

     

    This is WebForms, not winForms.

     System.Web.UI.WebControls.Label is a subclass of System.Web.UI.Control.

    This allows Label to become a part of ControlCollection.

     However, when iterating a ControlCollection:

    foreach (Control c in ControlCollection)

    you end up with the parent class, Control, not the subclass, hence having to check the type and then cast it again.

    Control only exposes common virtual properties, since text is only on a handfull of subcontrols, it is not a property of control. 

     Ugly.


     



  •  

     AH the beauty of dynamic languages... As long as you follow convention then figuring out who you are is unnecessary...

    In Flex2 depending on the component you can tell if it has a label or "text" (yes there is a difference, no i don't know why couldn't they jsut use text property everywhere)... So you can just see .hasOwnProperty("text") or .hasOwnProperty("label") and then just poof set that property.

    In strongly typed languages I suppose you can make a class that just takes the object, introspects it, and returns a function for setting the Text property (unless its not a function in which case its even worse), if null is returned then wah-wah, otherwise just set it. and no more giant if blocks.

    (go Ruby!)



  • @dlikhten said:

     

     AH the beauty of dynamic languages... As long as you follow convention then figuring out who you are is unnecessary...

    In Flex2 depending on the component you can tell if it has a label or "text" (yes there is a difference, no i don't know why couldn't they jsut use text property everywhere)... So you can just see .hasOwnProperty("text") or .hasOwnProperty("label") and then just poof set that property.

    In strongly typed languages I suppose you can make a class that just takes the object, introspects it, and returns a function for setting the Text property (unless its not a function in which case its even worse), if null is returned then wah-wah, otherwise just set it. and no more giant if blocks.

    (go Ruby!)

     

    Programming via Reflection could be implemented here, but I think that would make a slow solution even slower.

     What I really want to do is this:

    Type controlType = currentControl.getType()

    (currentControl as controlType).text = Foo;


    Yes, that looks like I'm casting an object to its own type, so it won't work. But it makes sense in my head dammit.



  • @AbbydonKrafts said:

    @belgariontheking said:
    Filed under: FUCKING HELL WHY DOES IT DELETE TWO CHARACTERS WHEN I HIT BACKSPACE ONCE?

    So it's not just me. I brought up a bunch of tag flaws in another sidebar post, and this was one of them. I'm gonna use that tag now.

    I don't think it was clear in my tag that this happens when I type my post, not my tag.  

    I can't wait until this becomes part of the tag cloud. 



  • create a Interface, call it HasLabelControl.  There does not need to be any methods in the interface.

    Create a subclass of each control you're interested in (Literal, LinkButton,  Label, etc).  For example, ourLiteral, ourLinkButton, etc.  

    For a class like ourLiteral, you'd inherit from Literal and HasLabelControl.  The ourLiteral class does not need any members, because all the functionality is in Literal already.  Use ourLiteral where you'd use a Literal.  (and the same for the others...)

     Then your code can be (I think, you'd have to check the syntax)

    HasControl c = foundControl as HasLabelControl;
    if (c != null) c.Text = ..........;




  • @Jonathan Holland said:

    @dlikhten said:

     

     AH the beauty of dynamic languages... As long as you follow convention then figuring out who you are is unnecessary...

    In Flex2 depending on the component you can tell if it has a label or "text" (yes there is a difference, no i don't know why couldn't they jsut use text property everywhere)... So you can just see .hasOwnProperty("text") or .hasOwnProperty("label") and then just poof set that property.

    In strongly typed languages I suppose you can make a class that just takes the object, introspects it, and returns a function for setting the Text property (unless its not a function in which case its even worse), if null is returned then wah-wah, otherwise just set it. and no more giant if blocks.

    (go Ruby!)

     

    Programming via Reflection could be implemented here, but I think that would make a slow solution even slower.

     What I really want to do is this:

    Type controlType = currentControl.getType()

    (currentControl as controlType).text = Foo;


    Yes, that looks like I'm casting an object to its own type, so it won't work. But it makes sense in my head dammit.

     

    Just letting you know... This is solved by using.... get this... Inheritence...

    If all your objects extends something called UIComponent and part of UI component is a text property... or say ControlComponent in your case. Just cast to ControlComponent and use ControlComponent.Text = "xxx makes the world go round".

    You can use interfaces instead if you don't want to change behavior. Using interfaces you can isolate behaviors and just check if its an instance of that interface.



  • @belgariontheking said:

    @AbbydonKrafts said:

    @belgariontheking said:
    Filed under: FUCKING HELL WHY DOES IT DELETE TWO CHARACTERS WHEN I HIT BACKSPACE ONCE?

    So it's not just me. I brought up a bunch of tag flaws in another sidebar post, and this was one of them. I'm gonna use that tag now.

    I don't think it was clear in my tag that this happens when I type my post, not my tag.  

    I can't wait until this becomes part of the tag cloud. 

     

    Let the revolution begin!



  • @dogbrags said:

    create a Interface, call it HasLabelControl.  There does not need to be any methods in the interface.

    Create a subclass of each control you're interested in (Literal, LinkButton,  Label, etc).  For example, ourLiteral, ourLinkButton, etc.  

    For a class like ourLiteral, you'd inherit from Literal and HasLabelControl.  The ourLiteral class does not need any members, because all the functionality is in Literal already.  Use ourLiteral where you'd use a Literal.  (and the same for the others...)

     Then your code can be (I think, you'd have to check the syntax)

    HasControl c = foundControl as HasLabelControl;
    if (c != null) c.Text = ..........;


     

     I understand how interfaces work. Doing that would involve rewriting all of the pages that use these controls to use the new controls that implement IOverComplicated.

     



  • @Jonathan Holland said:

    @Morbii said:

    Perhaps I'm reading the docs wrong, but doesn't System.Web.UI.WebControls.Label inherit from System.Windows.Forms.Label to get its Text member, which is then inherited from System.Windows.Forms.Control.  So... can't you just cast it as a System.Windows.Forms.Control and use the Text property?

     

    e.g.

    System.Windows.Forms.Control control = currentControl as System.Windows.Forms.Control;

    if(control!=null)

        control.Text = foundControl[_displayLabelColumn].ToString();

     

     

     

    This is WebForms, not winForms.

     

    I realized that this was WebForms, but it was my error anyway.  I was actually looking at the Microsoft.Office.Tools.Excel.Controls namespace whose Label class does derive from System.Windows.Forms and I assumed I was looking at System.Windows.WebForms.  Oops :o



  • I don't think there is any "clean" solution to this if the text properties are really on independant classes and only "happen" to share the same name. After all, the compiler would strip out the names anyway, so there is no kind of logical relation between the properties. (Reflection notwithstanding at least)

    Doesn't have C++ a kind of special pointer to object properties though? Maybe there is an equivalent in X.NET that you could use somehow? 



  • @belgariontheking said:

    I don't think it was clear in my tag that this happens when I type my post, not my tag.  

    I can't wait until this becomes part of the tag cloud. 

    Ahh.. that's even more strange. If you are using the tinyMCE editor.. well.. it's a loon, so anything's possible.



  • @PSWorx said:

    Doesn't have C++ a kind of special pointer to object properties though? Maybe there is an equivalent in X.NET that you could use somehow? 

    I don't think the C++ pointer-to-member is valid for different objects though (possibly by fluke if the classes happen to be layout compatible w.r.t to the member you're accessing, but I would not count on that, event if you had written those classes on your own).

    A different solution could be:

    • create a map/hash_table/something from Type -> Function, where the function sets the .Text property for the selected type
    • use your_map[ typeof(foo) ]( foo, new_text );

    Of course, this means that you have to write lots of functions that look like
    void set_text< typename Bar >( Control aFoo, string aText )
    {
    Bar b = (Bar)aFoo;
    b.Text = aText;
    }

    With C++ templates you could write a single definition of that function, dunno if C# (or whatever) has anything like templates though. Regardless, you still need to populate the table with Type->Function mappings, so you (probably) still have to enumerate all possible types manually at least once.



  • @Jonathan Holland said:

    new controls that implement IOverComplicated
     

    LOL... nice :)

     





  • "Reflection is slow" has to be qualified. It's certinaly not slow compared to all the nastiness that webforms does.



  • if (foundControl != null)
    {
    Type controlType = currentControl.GetType();    
    PropertyInfo property = controlType.GetProperty("Text");
    if (property != null)
    {
    property.SetValue(currentControl, foundControl[_displayLabelColumn].ToString(), null);
    }
    }

    Reflection isn't that slow.


  • Considered Harmful

    @Jonathan Holland said:

    @joe.edwards@imaginuity.com said:

    I was dealing with this same issue. I made a simple class that is used like so:

    string strValue = new ValueControl( myControl ).Value;

    The class figures out if it's using Text, Checked, or SelectedValue based on the kind of control. Then I was able to write a loop for all controls in a form to collect all the values, without having to do any special-cases.

    Edit: Yes, I know, a function could have done the same. The class actually did a few more things than that, though.

     

     Thats kind of backwards from what I need. I'm setting the text property, not retrieving it.

    This code is for this stupid localization system. Basicly, translators can use a tool to translate all the pages, which stores all text in a couple of database tables (mapping PageID and ControlID). Then when the page is rendered, all of the text gets swapped out with the proper localization.

     I fought long and hard for a different solution, but this is what we have to build. I did build in cacheing and defaulting to english without running the sproc, so it will only be a slow site for our global customers.

    The Value member of my ValueControl class was read-write. You could set the value, as well as get it.



  • OP is right; there is a better way:

    if (foundControl != null)
    {
    ITextControl textControl = currentControl as ITextControl;
    if (textControl != null)
    {
    textControl.Text = foundControl[_displayLabelColumn].ToString();
    }
    }

    All ASP.Net controls with a Text property implement (or atleast; should implement) ITextControl. Furthermore, a little known property of C#'s as operator is that it returns null if it can not cast the specified variable to the specified type.



  • I don't really have anything to say, I just wanted to add my vote for the tag. For the record, for me it doesn't actually delete two characters when I hit backspace once...



  •  Mucho gracias.

     I was unaware of the ITextControl interface. I am so glad I did not use the comment suggested a few posts up about creating my own subset of controls implemting IOverComplicated. Re-inventing the wheel :D



  • @PeriSoft said:

    I don't really have anything to say, I just wanted to add my vote for the tag. For the record, for me it doesn't actually delete two characters when I hit backspace once...

    Keep em coming.  It looks like we need more than 35 to get on the tag cloud.

    (Yes, I probaby care a bit too much about vandalizing the tag cloud) 



  • OMG... did someone copy some localization code that I've been working on and put it here? Except I don't actually work with anyone by the name of "Jonathan Holland"... there are two other Jonathans at my workplace...
    Seriously though, there are a few subtle differences between the code I'm maintaining and this code, but the resemblance is quite striking...

    By the way, I might want to warn anyone else who wanders down this path, that my coworker "B.R." (who wrote the original localization code I'm maintaining) discovered that in ASP.NET web forms (at least in 1.1, but that's another WTF), not all labels are actually labels! That is, some controls are actually subclasses of Label - for instance, all the Validator controls are really labels, and you need to set their ErrorMessage property, not their Text property, for them to work properly! :P


Log in to reply