// Implements the @bind(...) syntax private bool TryAddBindExpression(RazorIRToken token) { const string bindExpressionStart = "bind("; const string bindExpressionEnd = ")"; if (token.Content.StartsWith(bindExpressionStart) && token.Content.EndsWith(bindExpressionEnd)) { // Extract "expr" from "bind(expr)" var boundExpression = token.Content.Substring( bindExpressionStart.Length, token.Content.Length - bindExpressionStart.Length - bindExpressionEnd.Length); // We can't work out the final binding expression code yet, because we don't yet know what // type of element this is going onto (there might be a "type='checkbox'" or similar that // appears *after* the @bind(...)). So just store the expression for later use. _nextElementBoundExpression = MakeCSharpExpressionIRNode(token, boundExpression); return(true); } return(false); }
private static void AddIComponentRazorViewFactoryImplementation(ClassDeclarationIRNode classNode, RazorCodeDocument codeDoc) { // The Activator.CreateInstance feature that I added to the DNA runtime is very basic and doesn't // actually invoke the default constructor of the type being created. It just allocates memory for // the instance and returns it, without having run any constructor. This could be confusing if you // put constructor logic (such as field initializers) in your Razor page, given that we instantiate // it using Activator.CreateInstance. // As a workaround (without actually adding constructor support to Activator.CreateInstance, which // would be nontrivial), the Razor views privately implement an interface IComponentRazorViewFactory // that can return new instances of their own type. We can then just call this with normal .NET code. // This means we allocate memory for two instances of the view even though we're only using one, // but it's not going to matter much as the first instance will just be released to GC immediately. if (classNode.Interfaces == null) { classNode.Interfaces = new List <string>(); } classNode.Interfaces.Add(typeof(IRazorComponentFactory).FullName); var methodStatement = new CSharpStatementIRNode { Parent = classNode, Source = null }; classNode.Children.Add(methodStatement); var model = codeDoc.Items["DetectedModel"]; string content = ""; string isPage = ""; string addItems = ""; if (model != null) { content = $@"Model = new {model}();"; } if ((bool)codeDoc.Items["DetectedPage"]) { isPage += "classNode.IsPage = true;"; } if ((codeDoc.Items["DetectedPageMatches"]) != null) { var list = (List <string>)codeDoc.Items["DetectedPageMatches"]; addItems += "List<string> list = new List<string>();"; foreach (var item in list) { addItems += $"\r\n list.Add(\"{item}\");"; } addItems += "\r\n Items = list;"; } var razorToken = new RazorIRToken { Kind = RazorIRToken.TokenKind.CSharp, Parent = classNode, Content = $@" {typeof(RazorComponent).FullName} {typeof(IRazorComponentFactory).FullName}.{nameof(IRazorComponentFactory.Instantiate)}() {{ {content} var classNode = new {classNode.Name}(); {isPage} {addItems} return classNode; }}" }; methodStatement.Children.Add(razorToken); }