2

How can I create a form for dynamic properties?

So I understand this is how you dynamically get a property of an object:

ObjectName.GetType().GetProperty("nameofproperty")

How can I include the above in the form? I have tried doing this:

//loop through objects in model

 @Html.CheckBoxFor(model => m.ElementAt(i).Person.GetType().GetProperty("isAvailable"), new { @class = "person-avail" })

and within the model I have Person defined as a property like this:

public Person Person { get; set; }

and the Person class has it's own properties (the ones I want to create a form for):

public class Person 
{    
      public String name {get; set;}
      public bool isAvailable {get; set;}
      .
      .
      . etc
}

So at the moment this:

@Html.CheckBoxFor(model => m.ElementAt(i).Person.GetType().GetProperty("isAvailable"), new { @class = "person-avail" })

Gives me an exception saying:

Cannot implicitly convert type 'System.Reflection.PropertyInfo' to 'bool'

I understand what the problem is but how would I go about working around it?

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
user3281466
  • 491
  • 1
  • 7
  • 25
  • Possibly this question will help http://stackoverflow.com/questions/1196991/get-property-value-from-string-using-reflection-in-c-sharp – MattC Feb 19 '15 at 11:44
  • @MattC thanks but I have already figured out how to get the property info dynamically. The problem is that when I am creating the form I do not yet know what the value will be for a certain property - so my question is how to integrate the above into the form. – user3281466 Feb 19 '15 at 11:47
  • @MattC how would that add the user input from the form? it would just get it's current value. – user3281466 Feb 19 '15 at 12:21
  • Have you tried - @Html.CheckBoxFor(model => m.ElementAt(i).Person.GetType().GetProperty("isAvailable").GetValue(m.ElementAt(‌​i).Person), new { @class = "person-avail" }) – MattC Feb 19 '15 at 12:21
  • Oh ok I see, you want to have both read-write on a Dynamic property from a webform. If you have set the value initially then when the form is posted back to the Controller, the value from the checkbox should be in the Person Model object sent back. – MattC Feb 19 '15 at 12:22
  • Why aren't you binding the Person.isAvailable property against your checkbox? Why use reflection? – MattC Feb 19 '15 at 12:31
  • @MattC and also I tried just binding the property but it wouldn't save the data to the model (perhaps because I have an object within an object) hence I tried to find another way of doing it. – user3281466 Feb 19 '15 at 12:54

1 Answers1

0

Given the example you posted, it's not clear to me why you can't just write the code like this:

@Html.CheckBoxFor(model => m.ElementAt(i).Person.isAvailable,
    new { @class = "person-avail" })

I.e. since the Person property is already typed as Person, then the property named isAvailable ought to be there anyway.


That said, if for some reason you really must go through reflection for some unspecified reason, the issue you are having in the code you posted is that reflection only gives you the PropertyInfo object. To get the actual value, you need to apply that object to the original object to retrieve the property value. For example:

@Html.CheckBoxFor(model => (bool)m.ElementAt(i).Person.GetType()
    .GetProperty("isAvailable").GetValue(m.ElementAt(i).Person),
    new { @class = "person-avail" })

In other words, you have to pass the Person object instance reference to the PropertyInfo.GetValue() method. Since the method returns an object (i.e. the boxed bool value), you also have to cast back to bool.


<Aside>
Note: If you can cache the m.ElementAt(i).Person value, i.e. to use for both the call to GetType() and to pass to the GetValue() method, that would be a good idea. Unfortunately, I don't know web forms well enough to know what that syntax would look like or even if it's possible. If you can use the full lambda capabilities of C#, it could be done like this:

@Html.CheckBoxFor(model =>
    {
        Person person = m.ElementAt(i).Person;

        return (bool)person.GetType().GetProperty("isAvailable").GetValue(person);
    },
    new { @class = "person-avail" })

Otherwise, I assume you can figure that part out yourself. :)

</Aside>

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
  • thanks, I just tried this but when casting to boolean I get the following error: Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions. And I did try binding the property directly but it wouldn't save the data back to the model so I was looking for a different solution and this is why I want to do it with reflection – user3281466 Feb 20 '15 at 10:17