Reputation: 48197
I made my first MVC helper to split long strings in a table and I also validate if string is NULL and user can send NullString ='NA'
to show instead of empty string.
public static IHtmlString Split(
this HtmlHelper helper,
string source,
int size = 30,
string NullString = "")
Now I have the situation where the string is inside an object and this object can also be null.
@if (item.city == null)
{
<td>NA</td>
}
else
{
<td class="format">@item.city.name</td>
}
I want to do something generic, where I get an object and a property name. Then I can get the value from the object.
public static IHtmlString Split(
this HtmlHelper helper,
OBJECT source,
STRING property,
int size = 30,
string NullString = "")
Is there a way I can get source.property()
from a generic object?
by request full code of my current function
public static IHtmlString Split(this HtmlHelper helper, string source, int size = 30, string NullString = "")
{
TagBuilder tb = new TagBuilder("td");
tb.Attributes.Add("class", "format");
if (source == null)
{
tb.InnerHtml = NullString;
}
else if (source.Length < size)
{
tb.InnerHtml = source;
}
else
{
int middle = source.Length / 2;
int before = source.LastIndexOf(' ', middle);
int after = source.IndexOf(' ', middle + 1);
if (before == -1 || (after != -1 && middle - before >= after - middle))
{
middle = after;
}
else
{
middle = before;
}
string s1 = source.Substring(0, middle);
string s2 = source.Substring(middle + 1);
tb.InnerHtml = s1 + "<br />" + s2;
}
MvcHtmlString result = new MvcHtmlString(tb.ToString(TagRenderMode.Normal));
return result;
}
Upvotes: 1
Views: 816
Reputation: 1285
One approach would be to get the type of the object and then check for the existence of a property of the given name. Your helper method would accept the following arguments:
public static IHtmlString Split(
this HtmlHelper helper,
object source,
string property = "",
int size = 30,
string NullString = "")
Then you would get the System.Type
of the source object and decide whether to treat it as a string, or try to get the value of some specified property.
var stringToSplit = string.Empty;
if (source == null)
{
stringToSplit = NullString;
}
else if (string.IsNullOrEmpty(property))
{
stringToSplit = source.ToString();
}
else
{
Type type = source.GetType();
var propertyInfo = type.GetProperty(property);
if (propertyInfo != null)
{
var propertyValue = propertyInfo.GetValue(source);
stringToSplit = propertyValue != null ? propertyValue.ToString() : NullString;
}
else
{
stringToSplit = NullString;
}
}
Then you would check the length of stringToSplit
and split it if necessary.
Upvotes: 1
Reputation: 12448
This is how I might do it.
Use Razor templates to create an extension method, that accepts an object to check and the lambda to grab the string.
public static class HtmlHelperExtensions
{
public static IHtmlString AlternateTemplates<TModel>(this HtmlHelper htmlHelper, TModel model,
Func<TModel, string> stringProperty, Func<string, HelperResult> template,
Func<object, HelperResult> nullTemplate) where TModel : class
{
HelperResult result;
if (model != null)
{
var propertyValue = stringProperty.Invoke(model);
var splitValue = YourCustomSplitFunction(propertyValue); // TODO: Impliment yout split function to return a string (in this case)
result = template(splitValue);
}
else
{
result = nullTemplate(null);
}
htmlHelper.ViewContext.Writer.Write(result);
return MvcHtmlString.Empty;
}
}
Given a model like this:
public class ViewModel
{
public Region Region { get; set; }
}
public class Region
{
public string City { get; set; }
}
My controller action as an example:
In my view I could call:
@Html.AlternateTemplates(Model.Region, x => x.City, @<div>@item</div>, @<div>N/A</div>)
So, it's checking if the object I send in (in this case it's the Region
) is not null, then grab the property I specified (in this case City
), then render it against my first html/razor template, otherwise use the alternate.
Easy.
Some reading: http://www.prideparrot.com/blog/archive/2012/9/simplifying_html_generation_using_razor_templates
Upvotes: 1