Creating Razor helper methods for custom controls

  1. #1

    Creating Razor helper methods for custom controls

    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.FromStringExpression(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.GetExpressionText(expression));
                cmp.CallSetControlFor(ModelMetadata.FromLambdaExpression(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...l=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.
  2. #2
    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.
  3. #3
    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.
  4. #4
    Thanks, it works.
  5. #5
    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
  6. #6
    @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:)
  7. #7
    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.
  8. #8
    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.

Similar Threads

  1. [CLOSED] Custom TextFieldfor helper
    By infonext in forum 2.x Premium Help
    Replies: 7
    Last Post: Jan 09, 2014, 4:25 AM
  2. Razor: Custom Controls: 2 Controls as 1
    By bright in forum 2.x Help
    Replies: 0
    Last Post: Nov 09, 2013, 11:42 AM
  3. Direct Methods and Custom Control
    By Zdenek in forum 1.x Help
    Replies: 0
    Last Post: Apr 19, 2012, 10:18 PM
  4. Replies: 3
    Last Post: Feb 21, 2012, 7:46 AM
  5. Replies: 3
    Last Post: Jan 04, 2011, 11:47 AM

Tags for this Thread

Posting Permissions