自定义视图引擎

自定义视图引擎
创建自己的视图引擎
public class HoTMeaTViewEngine : VirtualPathProviderViewEngine
    {
        public HoTMeaTViewEngine()
        {
            base.ViewLocationFormats = new string[] { "~/Views/{1}/{0}.html" };
           
            base.PartialViewLocationFormats = base.ViewLocationFormats;
        }

        protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
        {
            return new HoTMeaTView(viewPath, masterPath ?? "");
        }

        protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
        {
            return new HoTMeaTView(partialPath, "");
        }
    }
创建自己的视图
public class HoTMeaTView : IView
    {
        static Dictionary<string, string> cachedFiles = new Dictionary<string, string>();

        static Regex codeParser = new Regex(@"
(/<code(/s+(?<AttributeName>/w+)/s*=/s*""(?<AttributeValue>[^>""]*)"")*/s*//>)
|
(/<code(/s+(?<AttributeName>/w+)/s*=/s*""(?<AttributeValue>[^>""]*)"")*/s*/>/s*
    (/s*/<(?<ParameterName>/w+)/>(?<ParameterValue>[/s/S]*?)/<//k<ParameterName>/>/s*)*
/s*/</code/>)
", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);

        static Regex controlsParser = new Regex(@"
/<(?<Control>(listView))(/s+(?<AttributeName>/w+)/s*=/s*""(?<AttributeValue>[^>""]*)"")*/s*/>/s*
    (/s*/<(?<ParameterName>/w+)/>(?<ParameterValue>[/s/S]*?)/<//k<ParameterName>/>/s*)*
/s*/<//k<Control>/>", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);

        public HoTMeaTView(string viewPath, string masterPath)
        {
            this.ViewPath = viewPath;

            this.MasterPath = masterPath;
        }

        public ViewContext CurrentViewContext { get; private set; }

        public string ViewPath { get; private set; }

        public string MasterPath { get; private set; }

        public void Render(ViewContext viewContext, TextWriter writer)
        {
            this.CurrentViewContext = viewContext;

            if (cachedFiles.ContainsKey(this.ViewPath) == false)
            {
                cachedFiles.Add(this.ViewPath, File.ReadAllText(viewContext.HttpContext.Server.MapPath(this.ViewPath)));
            }

            string sourceCode = cachedFiles[this.ViewPath];

            sourceCode = controlsParser.Replace(sourceCode, delegate(Match currentMatch)
            {
                SettingsDicitonary settings = this.GetSettings(currentMatch);

                return this.EvaluateControl(currentMatch.Groups["Control"].Value.ToLower(), settings.Attributes, settings.Parameters, currentMatch.Value);
            });

            sourceCode = codeParser.Replace(sourceCode, delegate(Match currentMatch)
            {
                SettingsDicitonary settings = this.GetSettings(currentMatch);

                return this.EvaluateCode(settings.Attributes["class"], settings.Attributes["method"], settings.Parameters, currentMatch.Value);
            });

            writer.Write(sourceCode);
        }

        private string EvaluateCode(string className, string methodName, Dictionary<string, string> parameters, string originalSource)
        {
            Type targetType = Type.GetType(className, false, false);

            if (targetType == null)
            {
                return originalSource;
            }

            // First attempt with a static method.
            MethodInfo targetMethod = targetType.GetMethods(BindingFlags.Public | BindingFlags.Static)
                .Where(method => method.Name == methodName)
                .Where(method => method.GetParameters()
                    .Count(parameter => parameters.Keys.Contains(parameter.Name)) == parameters.Count)
                .FirstOrDefault();

            if (targetMethod != null)
            {
                return string.Format("{0}", targetMethod.Invoke(null, this.GetConvertedValues(parameters, targetMethod.GetParameters())));
            }

            // Second attempt with an instance method.
            targetMethod = targetType.GetMethods(BindingFlags.Public | BindingFlags.Instance)
                .Where(method => method.Name == methodName)
                .Where(method => method.GetParameters()
                    .Count(parameter => parameters.Keys.Contains(parameter.Name)) == parameters.Count)
                .FirstOrDefault();

            if (targetMethod != null)
            {
                return string.Format("{0}", targetMethod.Invoke(Activator.CreateInstance(targetType), this.GetConvertedValues(parameters, targetMethod.GetParameters())));
            }

            return originalSource;
        }

        private string EvaluateControl(string controlName, Dictionary<string, string> attributes, Dictionary<string, string> parameters, string originalSource)
        {
            switch (controlName)
            {
                // Note... make this a generic alias for the "code" block??? that would be awesome!
                case "listview":
                    {
                        return ListView.Render((IEnumerable)this.GetBoundValue(attributes["source"]), parameters["itemTemplate"]);
                    }
            }

            return originalSource;
        }

        private object GetBoundValue(string bindingString)
        {
            Binding binding = BindingHelper.Parse(bindingString);

            if (binding != null)
            {
                switch (binding.Source.ToLower())
                {
                    case "request":
                        {
                            return this.CurrentViewContext.HttpContext.Request[binding.Property];
                        }

                    case "routedata":
                        {
                            return this.CurrentViewContext.RouteData.Values[binding.Property];
                        }

                    case "viewdata":
                        {
                            return this.CurrentViewContext.ViewData[binding.Property];
                        }
                }
            }

            return null;
        }

        private object[] GetConvertedValues(Dictionary<string, string> parameters, ParameterInfo[] parameterInfos)
        {
            object[] result = new object[parameterInfos.Length];

            for (int i = 0; i < parameterInfos.Length; i++)
            {
                string currentValue = parameters.First(param => param.Key == parameterInfos[i].Name).Value;

                object boundValue = this.GetBoundValue(currentValue);

                if (boundValue != null)
                {
                    result[i] = boundValue;
                }
                else
                {
                    result[i] = Convert.ChangeType(currentValue, parameterInfos[i].ParameterType);
                }
            }

            return result;
        }

        private SettingsDicitonary GetSettings(Match currentMatch)
        {
            SettingsDicitonary result = new SettingsDicitonary();

        //    { // Attributes
                Group attributeNames = currentMatch.Groups["AttributeName"];

                Group attributeValues = currentMatch.Groups["AttributeValue"];

                for (int i = 0, length = attributeNames.Captures.Count; i < length; i++)
                {
                    result.Attributes.Add(attributeNames.Captures[i].Value, attributeValues.Captures[i].Value);
                }
        //    }

        //    { // Parameters
                Group parameterNames = currentMatch.Groups["ParameterName"];

                Group parameterValues = currentMatch.Groups["ParameterValue"];

                for (int i = 0, length = parameterNames.Captures.Count; i < length; i++)
                {
                    result.Parameters.Add(parameterNames.Captures[i].Value, parameterValues.Captures[i].Value);
                }
        //    }

            return result;
        }

        class SettingsDicitonary
        {
            public readonly Dictionary<string, string> Attributes = new Dictionary<string, string>();

            public readonly Dictionary<string, string> Parameters = new Dictionary<string, string>();
        }
    }
创建BindingHelper类
public class Binding
    {
        public string Source { get; set; }

        public string Property { get; set; }
    }

    public static class BindingHelper
    {
        private static Regex bindingParser = new Regex(@"^/{(?<Source>Binding|ViewData)/s+(?<Property>/w+)/}$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);

        private static Regex propertyBindingParser = new Regex(@"/{Binding/s+(?<Property>/w+)/}", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);

        public static Binding Parse(string bindingString)
        {
            Match bindingMatch = bindingParser.Match(bindingString);

            if (bindingMatch.Success)
            {
                return new Binding
                {
                    Source = bindingMatch.Groups["Source"].Value,
                    Property = bindingMatch.Groups["Property"].Value,
                };
            }
            else
            {
                return null;
            }
        }

        public static string PerformBinding(string formatString, object item)
        {
            Type itemType = item.GetType();

            string returnString=propertyBindingParser.Replace(formatString, delegate(Match binding)
            {

                string property=binding.Groups["Property"].Value;

                PropertyInfo info=itemType.GetProperty(property);

                string myString=string.Format("{0}",info.GetValue(item, null));


                return myString;    
            });

            return returnString;


        }
    }
创建ListView控件

    public static class ListView
    {
        public static string Render(IEnumerable source, string itemTemplate)
        {
            StringBuilder resultBuilder = new StringBuilder();

            foreach (object item in source)
            {
                resultBuilder.Append(BindingHelper.PerformBinding(itemTemplate, item));
            }

            return resultBuilder.ToString();
        }
    }
创建实用类
public class TimeHelper
    {
        public static DateTime GetCurrentTime()
        {
            return DateTime.Now;
        }

        public static string GetCurrentTime(string formatString)
        {
            return DateTime.Now.ToString(formatString);
        }
    }
使用方法
配置全局应用程序
    protected void Application_Start()
        {
            RegisterRoutes(RouteTable.Routes);
            ViewEngines.Engines.Clear();
            ViewEngines.Engines.Add(new HoTMeaTViewEngine());
        }
public ActionResult Index()
        {
            ViewData["People"] = new Person[]
            {
                new Person{FirstName="Timothy", LastName="Khouri"},
                new Person{FirstName="Jonathan", LastName="Carter"},
                new Person{FirstName="Travis", LastName="Sheppard"},
            };

            return View();
        }

        public class Person
        {
            public string FirstName { get; set; }

            public string LastName { get; set; }
        }
<html>
<head>
    <title>Singing Eels - "HoT MeaT" View Engine!</title>
   
    <style type="text/css">
    p
    {
        margin: 0;
        padding: 1em;
    }
    div.sample
    {
        margin-bottom: 1em;
        border: solid 1px #369;
    }
    </style>
   
</head>
<body>
    <h1>
        Singing Eels - "HoT MeaT" View Engine!</h1>
    <div class="sample">
        <p>
            The time on the server is:
            <span style="color: #f00;">
                <code class="Eels.TimeHelper" method="GetCurrentTime" />
            </span>
        </p>
    </div>
    <div class="sample">
        <p>
            The time on the server (formatted) is:
            <span style="color: #f00;">
                <code class="Eels.TimeHelper" method="GetCurrentTime">
                    <formatString>dddd, MMMM dd, yyyy</formatString>
                </code>
            </span>
        </p>
    </div>
    <div class="sample">
        <p>
            Check out some data-binding in HoTMeaT:</p>
        <ul>
            <listView source="{ViewData People}">
                <itemTemplate>
                    <li>{Binding LastName}, {Binding FirstName}</li>
                </itemTemplate>
            </listView>
        </ul>
    </div>
</body>
</html>


你可能感兴趣的:(自定义视图引擎)