PDA

View Full Version : Creating Razor helper methods for custom controls



Daniil
Dec 26, 2013, 1:58 PM
The inheritance is one of the OOP's concepts. Using Ext.NET you are able to use that concept as well, i.e. derive from existing Ext.NET controls.

The developers who use MVC and Razor View Engine are aware about special helper methods to create the Ext.NET controls, e.g:

@Html.X().TextField().Text("Hello!")
@Html.X().TextFieldFor(m => m.Name)

In this tutorial I will explain how to create such helper methods for your custom controls.

1. The first step is creating a custom control itself. Let's create the MyTextField control. A simple one, just for sake of demonstrating.

MyTextField.cs

using System.Web.Mvc;

namespace Ext.Net.MyExtensions
{
public partial class MyTextField : TextField
{
public MyTextField() : base() { }

private string prefixText;

public string PrefixText
{
get
{
return prefixText;
}
set
{
prefixText = value;
this.Text = value + this.Text;
}
}
}
}

2. The second step is creating a special builder class for that custom control.

It should look like this.

MyTextFieldBuilder.cs

namespace Ext.Net.MyExtensions
{
public partial class MyTextField
{
new public partial class Builder<TMyTextField, TBuilder> : TextField.Builder<TMyTextField, TBuilder>
where TMyTextField : MyTextField
where TBuilder : Builder<TMyTextField, TBuilder>
{
public Builder(TMyTextField component) : base(component) { }

public virtual TBuilder PrefixText(string prefixText)
{
this.ToComponent().PrefixText = prefixText;
return this as TBuilder;
}
}

public partial class Builder : MyTextField.Builder<MyTextField, MyTextField.Builder>
{
public Builder() : base(new MyTextField()) { }

public Builder(MyTextField component) : base(component) { }
}
}
}

The owners of Premium Support Subscription who have access to the Ext.NET sources have a good possibility to avoid creating builders for custom controls manually, because we have a special utility to generate it automatically. If someone is interested in that, please post below and I will provide you with a small instruction how to do that.

3. The next step is getting your custom control in Html.X().It is possible to do via creating the extensions methods for the BuilderFactory class (which is returned by Html.X() method).

XExtensions.cs
using System;
using System.Web.Mvc;
using System.Linq.Expressions;

namespace Ext.Net.MyExtensions
{
public static class XExtensions
{
public static MyTextField.Builder MyTextField(this BuilderFactory x)
{
return new MyTextField.Builder(new MyTextField()
{
ViewContext = x.HtmlHelper != null ? x.HtmlHelper.ViewContext : null
});
}

public static MyTextField.Builder MyTextField(this BuilderFactory x, string labelText)
{
return new MyTextField.Builder(new MyTextField()
{
ViewContext = x.HtmlHelper != null ? x.HtmlHelper.ViewContext : null,
PrefixText = labelText
});
}

// MyTextFieldFor helper methods for Ext.NET > v2.4 (starting from the SVN revision #5584)
public static MyTextField.Builder MyTextFieldFor(this BuilderFactory x, string expression, bool setId = true, Func<object, object> convert = null, string format = null)
{
return x.InitFieldForBuilder<MyTextField, MyTextField.Builder>(expression, setId, convert, format);
}

public static MyTextField.Builder MyTextFieldFor<TModel, TProperty>(this BuilderFactory<TModel> x, Expression<Func<TModel, TProperty>> expression, bool setId = true, Func<object, object> convert = null, string format = null)
{
return x.InitFieldForBuilder<MyTextField, MyTextField.Builder, TProperty>(expression, setId, convert, format);
}

// MyTextFieldFor helper methods for Ext.NET <= v2.4
/*
public static MyTextField.Builder MyTextFieldFor(this BuilderFactory x, string expression, bool setId = true, Func<object, object> convert = null, string format = null)
{
MyTextField.Builder builder = new MyTextField.Builder();
var cmp = builder.ToComponent();

cmp.ViewContext = x.HtmlHelper.ViewContext;
cmp.IDFromControlFor = setId;
cmp.ConvertControlForValue = convert;
cmp.FormatControlForValue = format;

builder.ControlFor(expression);
cmp.CallSetControlFor(ModelMetadata.FromStringExpr ession(expression, x.HtmlHelper.ViewData));

return builder;
}

public static MyTextField.Builder MyTextFieldFor<TModel, TProperty>(this BuilderFactory<TModel> x, Expression<Func<TModel, TProperty>> expression, bool setId = true, Func<object, object> convert = null, string format = null)
{
MyTextField.Builder builder = new MyTextField.Builder();
var cmp = builder.ToComponent();
cmp.ViewContext = x.HtmlHelper.ViewContext;
cmp.IDFromControlFor = setId;
cmp.ConvertControlForValue = convert;
cmp.FormatControlForValue = format;

builder.ControlFor(ExpressionHelper.GetExpressionT ext(expression));
cmp.CallSetControlFor(ModelMetadata.FromLambdaExpr ession(expression, x.HtmlHelper.ViewData));
return builder;
}
*/
}
}

If you use Ext.NET <= v2.4, then for the MyTextFieldFor helpers you have to add this method to the MyTextField class:


public void CallSetControlFor(ModelMetadata meta)
{
this.SetControlFor(meta);
}

If you want to use, for example, your own Html.Y() instead of Html.X(), here is an example how to do that, see ControlFactory.cs and YExtensions.cs.
http://forums.ext.net/showthread.php?24894&p=111217&viewfull=1#post111217

4. The usage.

Model

namespace Ext.Net.MVC.Examples.Models
{
public class Employee
{
public string Name { get; set; }
}
}

View

@model Ext.Net.MVC.Examples.Models.Employee

@using Ext.Net.MyExtensions;

<!DOCTYPE html>
<html>
<head>
<title>Ext.Net.MVC v2 Example</title>
</head>
<body>
@Html.X().ResourceManager()

@Html.X().MyTextField().PrefixText("1: ")

@Html.X().MyTextField("2: ")

@Html.X().MyTextFieldFor(m => m.Name)
</body>
</html>

Controller

using System.Web.Mvc;

namespace Work2MVC.Controllers
{
public class RazorController : Controller
{
public ActionResult Index()
{
return View(new Ext.Net.MVC.Examples.Models.Employee() { Name = "John" });
}
}
}


If you have any questions or suggestions, you are welcome.

alex303
Dec 28, 2013, 4:46 PM
Daniil, thanks for guide.

> If someone is interested in that, please post below and I will provide you with a small instruction how to do that.

Interested, please provide that instrucation.

Daniil
Dec 30, 2013, 4:11 AM
Thank you for the request. Here you are.

1. Download the Ext.NET sources from SVN. For example, the trunk:
http://svn.ext.net/premium/trunk/Ext.Net/

2. Put the .cs file with a custom control inside the Ext folder of the Ext.Net project.

3. Mark with a [Meta] attribute the custom control class and and all the properties which you want to be in a builder class.

MyTextField with [Meta]

using System.Web.Mvc;

namespace Ext.Net.MyExtensions
{
[Meta]
public partial class MyTextField : TextField
{
public MyTextField() : base() { }

private string prefixText;

[Meta]
public string PrefixText
{
get
{
return prefixText;
}
set
{
prefixText = value;
this.Text = value + this.Text;
}
}
}
}

4. Run Ext.Net\Build\Meta\Parser\Ext.Net.Meta.Parser.exe

5. Run Ext.Net\Build\Meta\Parser\Ext.Net.Meta.Factory.exe

6. See Ext.Net\Factory\Builder\MyTextFieldBuilder.cs
Among the things it will contain the builder class. You might need to remove the things which are not compiled.

alex303
Dec 30, 2013, 7:35 PM
Thanks, it works.

ALobpreis
Jul 18, 2014, 2:59 PM
One small comment about this code:


set
{
prefixText = value;
this.Text = value + this.Text;
}

When you change the prefix, it doesn't actually change it but just inserts it before the previous one. For example, you can end up having something like "Prefix2Prefix1OriginalText". One possible solution is this:


public string PrefixText
{
get
{
return prefixText;
}
set
{
prefixText = value;
}
}


public override string Text
{
get
{
return prefixText + base.Text;
}
}


Regards,

Andrew

Daniil
Jul 21, 2014, 1:59 PM
@ALobpreis, thank you for the comment.

Well, the MyTextField control is quite a fake one. I just needed a very simple custom control with any visual effect.

Anyway, thanks. At least, someone more has read the tutorial:)

sishco
Apr 28, 2016, 3:14 PM
Hello.

I want to make a custom control for a panel.

But i don't find the method "InitPanelForBuilder<..." like your example "InitFieldForBuilder<MyTextField, ..." in the class BuilderFactory.

It is posible to create a custom control with a panel and use it with the helper?

Regards.

Daniil
Apr 28, 2016, 7:29 PM
Hello @sishco,


It is posible to create a custom control with a panel and use it with the helper?

Yes, it is possible.

InitFieldForBuilder is only required for helpers with For at the end, lile MyTextFieldFor

A Panel doesn't have any PanelFor helpers. So, this part can be skipped for your custom Panel.