private Dictionary <string, CodePropertyReferenceExpression> CreatePropertiesForResources(IEnumerable <Resource> resources) { return(resources.ToDictionary(resource => resource.Key, resource => { DataTemplateResource dataTemplateResource = resource as DataTemplateResource; Tuple <CodeMemberField, CodeMemberProperty> result; if (dataTemplateResource != null) // in case of data templates { const string type = "Storm.Mvvm.DataTemplate"; result = CodeGeneratorHelper.GenerateProxyProperty(resource.PropertyName, type, fieldReference => new List <CodeStatement> { // _field = new DataTemplate(); new CodeAssignStatement(fieldReference, new CodeObjectCreateExpression(CodeGeneratorHelper.GetTypeReferenceFromName(type))), // _field.ViewId = Resource.Id.*** new CodeAssignStatement(new CodePropertyReferenceExpression(fieldReference, "ViewId"), CodeGeneratorHelper.GetAndroidResourceReference(ResourcePart.Layout, dataTemplateResource.ViewId)), // _field.LayoutInflater = LayoutInflater; new CodeAssignStatement(new CodePropertyReferenceExpression(fieldReference, "LayoutInflater"), GetLayoutInflaterReference()), // _field.ViewHolderType = typeof(viewholder class) new CodeAssignStatement(new CodePropertyReferenceExpression(fieldReference, "ViewHolderType"), new CodeTypeOfExpression(string.Format("{0}.{1}", Configuration.GeneratedNamespace, dataTemplateResource.ViewHolderClassName))), }); } else { // create a proxy property to handle the resource string type = resource.Type; Dictionary <string, string> assignments = resource.Properties; result = CodeGeneratorHelper.GenerateProxyProperty(resource.PropertyName, type, fieldReference => CodeGeneratorHelper.GenerateStatementsCreateAndAssign(fieldReference, type, assignments)); } Fields.Add(result.Item1); Properties.Add(result.Item2); return CodeGeneratorHelper.GetPropertyReference(result.Item2); })); }
private void GenerateCommandParameterProperties(List <ExpressionContainer> expressionContainers) { foreach (IGrouping <string, ExpressionContainer> expressions in expressionContainers.GroupBy(x => x.TargetObject)) { const string attributeName = "CommandParameter"; Regex commandParameterEventRegex = new Regex("^(?<eventName>[a-zA-Z0-9_]+)\\." + attributeName, RegexOptions.Compiled | RegexOptions.IgnoreCase); List <ExpressionContainer> commandParameterEventExpressions = expressions.Where(x => commandParameterEventRegex.IsMatch(x.TargetField)).ToList(); ExpressionContainer commandParameterExpression = expressions.SingleOrDefault(x => attributeName.Equals(x.TargetField, StringComparison.InvariantCultureIgnoreCase)); commandParameterEventExpressions.ForEach(x => x.IsCommandParameterExpression = true); if (commandParameterExpression != null) { commandParameterExpression.IsCommandParameterExpression = true; } foreach (ExpressionContainer expression in commandParameterEventExpressions) { //find associated event (if exists) string eventName = commandParameterEventRegex.Match(expression.TargetField).Groups["eventName"].Value; ExpressionContainer associatedExpression = expressions.FirstOrDefault(x => eventName.Equals(x.TargetField, StringComparison.InvariantCultureIgnoreCase) && !x.IsCommandParameterExpression); if (associatedExpression != null) { // create proxy property CommandParameterProxy to handle this var result = CodeGeneratorHelper.GenerateProxyProperty(NameGeneratorHelper.GetCommandParameterName(), "CommandParameterProxy"); Properties.Add(result.Item2); Fields.Add(result.Item1); string propertyName = CodeGeneratorHelper.GetPropertyReference(result.Item2).PropertyName; // retarget the binding expression to this new property and to the Value field expression.TargetObject = propertyName; expression.TargetField = "Value"; associatedExpression.CommandParameterTarget = propertyName; } } if (commandParameterExpression != null) { // create proxy property CommandParameterProxy to handle this var result = CodeGeneratorHelper.GenerateProxyProperty(NameGeneratorHelper.GetCommandParameterName(), "CommandParameterProxy"); Properties.Add(result.Item2); Fields.Add(result.Item1); string propertyName = CodeGeneratorHelper.GetPropertyReference(result.Item2).PropertyName; // retarget the binding expression to this new property and to the Value field commandParameterExpression.TargetObject = propertyName; commandParameterExpression.TargetField = "Value"; foreach (ExpressionContainer associatedExpression in expressions.Where(x => string.IsNullOrEmpty(x.CommandParameterTarget) && !x.IsCommandParameterExpression)) { associatedExpression.CommandParameterTarget = propertyName; } } } }
private CodePropertyReferenceExpression CreateLocalizationServiceProperty() { CodeMethodReferenceExpression resolveMethodReference = new CodeMethodReferenceExpression( new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(CodeGeneratorHelper.GetTypeReferenceFromName("DependencyService")), "Container"), "Resolve", CodeGeneratorHelper.GetTypeReferenceFromName("ILocalizationService") ); CodeMethodInvokeExpression invokeMethod = new CodeMethodInvokeExpression(resolveMethodReference); Tuple <CodeMemberField, CodeMemberProperty> result = CodeGeneratorHelper.GenerateProxyProperty(NameGeneratorHelper.LOCALIZATION_SERVICE_PROPERTY_NAME, "ILocalizationService", invokeMethod); Fields.Add(result.Item1); Properties.Add(result.Item2); return(CodeGeneratorHelper.GetPropertyReference(result.Item2)); }
public void Preprocess(List <XmlAttribute> expressionAttributes, List <Resource> resources, List <IdViewObject> viewElements) { // Create all properties for viewElements foreach (IdViewObject viewElement in viewElements) { Tuple <CodeMemberField, CodeMemberProperty> result = CodeGeneratorHelper.GenerateProxyProperty(viewElement.Id, viewElement.TypeName, new CodeMethodInvokeExpression(GetFindViewByIdReference(viewElement.TypeName), CodeGeneratorHelper.GetAndroidResourceReference(ResourcePart.Id, viewElement.Id))); Fields.Add(result.Item1); Properties.Add(result.Item2); } // Generate property for ILocalizationService LocalizationService CodePropertyReferenceExpression localizationServiceReference = CreateLocalizationServiceProperty(); // Eval all expressions List <ExpressionContainer> expressions = (from attribute in expressionAttributes let expressionResult = EvaluateExpression(attribute.Value) where expressionResult != null select new ExpressionContainer { Expression = expressionResult, TargetObject = attribute.AttachedId, TargetField = attribute.LocalName, IsTargetingResource = false, }).ToList(); // Affect a property name to all resources and check if some has expression as attribute value foreach (Resource res in resources) { res.PropertyName = NameGeneratorHelper.GetResourceName(); foreach (KeyValuePair <string, string> propertyItem in res.Properties.Where(propertyItem => ParsingHelper.IsExpressionValue(propertyItem.Value)).ToList()) { res.Properties.Remove(propertyItem.Key); Expression expr = EvaluateExpression(propertyItem.Value); if (expr != null) { if (CheckCorrectExpressionInResource(expr)) { Log.LogError("Expression {0} is invalid in a resource context (you cannot use binding)", propertyItem.Value); } else { expressions.Add(new ExpressionContainer { Expression = expr, TargetObject = res.PropertyName, TargetField = propertyItem.Key, IsTargetingResource = true, }); } } } } // Check if all resources are declared and filter those we need Dictionary <string, Resource> neededResource = new Dictionary <string, Resource>(); List <string> resourceKeys = expressions.SelectMany(x => GetUsedResources(x.Expression)).Distinct().ToList(); foreach (string key in resourceKeys) { Resource res = resources.FirstOrDefault(x => key.Equals(x.Key, StringComparison.InvariantCultureIgnoreCase)); if (res == null) { Log.LogError("Resource with key {0} does not exists", key); } else { neededResource.Add(key, res); } } // Go through all binding expression and find those where we need to declare implicit resources // Will also remove all Template & TemplateSelector fields in BindingExpression // to only have a fully prepared adapter foreach (Expression bindingExpression in expressions.SelectMany(expression => GetBindingExpressions(expression.Expression)).ToList()) { if (bindingExpression.Has(BindingExpression.TEMPLATE)) { // create a template selector string templateSelectorKey = NameGeneratorHelper.GetResourceKey(); string templateSelectorPropertyName = NameGeneratorHelper.GetResourceName(); neededResource.Add(templateSelectorKey, new Resource(templateSelectorKey) { PropertyName = templateSelectorPropertyName, ResourceElement = null, Type = Configuration.DefaultTemplateSelector }); expressions.Add(new ExpressionContainer { Expression = bindingExpression[BindingExpression.TEMPLATE], TargetField = Configuration.DefaultTemplateSelectorField, TargetObject = templateSelectorPropertyName, IsTargetingResource = true, }); bindingExpression.Remove(BindingExpression.TEMPLATE); ResourceExpression templateSelectorResourceExpression = new ResourceExpression(); templateSelectorResourceExpression.Add(ResourceExpression.KEY, new TextExpression { Value = templateSelectorKey }); bindingExpression.Add(BindingExpression.TEMPLATE_SELECTOR, templateSelectorResourceExpression); } if (bindingExpression.Has(BindingExpression.TEMPLATE_SELECTOR)) { // create an adapter string adapterKey = NameGeneratorHelper.GetResourceKey(); string adapterName = NameGeneratorHelper.GetResourceName(); neededResource.Add(adapterKey, new Resource(adapterKey) { PropertyName = adapterName, ResourceElement = null, Type = Configuration.DefaultAdapter }); expressions.Add(new ExpressionContainer { Expression = bindingExpression[BindingExpression.TEMPLATE_SELECTOR], TargetField = Configuration.DefaultAdapterField, TargetObject = adapterName, IsTargetingResource = true, }); bindingExpression.Remove(BindingExpression.TEMPLATE_SELECTOR); ResourceExpression adapterResourceExpression = new ResourceExpression(); adapterResourceExpression.Add(ResourceExpression.KEY, new TextExpression { Value = adapterKey }); bindingExpression.Add(BindingExpression.ADAPTER, adapterResourceExpression); } } // In order to check if all adapter are not used more than once since we need them to be unique target Dictionary <string, bool> usedAdapter = new Dictionary <string, bool>(); foreach (ExpressionContainer expression in expressions.Where(x => x.Expression.IsOfType(ExpressionType.Binding)).ToList()) { Expression bindingExpression = expression.Expression; if (bindingExpression.Has(BindingExpression.ADAPTER)) { // expression in Adapter could only be Resource (since it's an android platform specific things, a binding expression would not have any sense) Expression resourceExpression = bindingExpression[BindingExpression.ADAPTER]; string adapterKey = resourceExpression.GetValue(ResourceExpression.KEY); Resource adapterResource = neededResource[adapterKey]; if (usedAdapter.ContainsKey(adapterKey)) { Log.LogError("The adapter with key {0} is used more than once which could lead to issue, you need one adapter per use !", adapterKey); } else { usedAdapter.Add(adapterKey, true); } // remove the adapter property bindingExpression.Remove(BindingExpression.ADAPTER); // store old target info string oldTargetField = expression.TargetField; string oldTargetObject = expression.TargetObject; bool oldTargetType = expression.IsTargetingResource; // retarget the binding expression to be targeted to Adapter.Collection expression.TargetField = "Collection"; expression.TargetObject = adapterResource.PropertyName; expression.IsTargetingResource = false; //TODO : false for debug mode only, need to see what we can do about that ? // add a new expression to target the old object/field couple and affect the adapter with the resource expression expressions.Add(new ExpressionContainer { IsTargetingResource = oldTargetType, TargetField = oldTargetField, TargetObject = oldTargetObject, Expression = resourceExpression, }); } } // Create all properties for resources Dictionary <string, CodePropertyReferenceExpression> resourceReferences = CreatePropertiesForResources(neededResource.Values); // Generate all properties to handle CommandParameter and retarget all expressions if needed GenerateCommandParameterProperties(expressions); // Create a setup resources method to initalize resources with all {Resource ...} and {Translation ...} expressions List <ExpressionContainer> translationExpressions = expressions.Where(x => x.Expression.IsOfType(ExpressionType.Translation)).ToList(); List <ExpressionContainer> expressionsTargetingResources = expressions.Where(x => x.IsTargetingResource && x.Expression.IsOfType(ExpressionType.Resource)).ToList(); List <ExpressionContainer> resourceExpressions = expressions.Where(x => !x.IsTargetingResource && x.Expression.IsOfType(ExpressionType.Resource)).ToList(); List <ExpressionContainer> bindingExpressions = expressions.Where(x => !x.IsTargetingResource && x.Expression.IsOfType(ExpressionType.Binding)).ToList(); CodeMethodReferenceExpression assignTranslationMethodReference = CreateAssignTranslationMethod(translationExpressions, localizationServiceReference); CodeMethodReferenceExpression setupResourcesReference = CreateSetupResourcesMethod(expressionsTargetingResources, resourceReferences); CodeMethodReferenceExpression setupResourceForViewElement = CreateSetupResourceForViewElementMethod(resourceExpressions, resourceReferences); CreateBindingOverrideMethod(bindingExpressions, localizationServiceReference, resourceReferences, assignTranslationMethodReference, setupResourcesReference, setupResourceForViewElement); }