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); }