protected override void WriteBindingFragmentProperty(State state, LayoutWidget widget, string resourceNamespace) { EnsureArgument(state, nameof(state)); EnsureArgument(widget, nameof(widget)); WriteBindingLambdaPropertyGetter(state, widget, resourceNamespace, "FindFragment", true); }
protected void WriteBindingPropertyBackingField(State state, LayoutWidget widget) { EnsureArgument(state, nameof(state)); EnsureArgument(widget, nameof(widget)); WriteLocationDirective(state, widget); WriteLineIndent(state, GetBindingPropertyBackingField(widget)); WriteResetLocation(state); }
void WritePropertyDeclaration(State state, LayoutWidget widget, bool isLambda) { WriteIndent(state, $"public {widget.Type} {GetValidPropertyName (state, widget)} "); if (isLambda) { state.Write("=> "); } else { state.WriteLine("{"); } }
void DetermineWidgetType (LayoutWidget widget, bool needsFullCheck) { if (!needsFullCheck && widget.WidgetType != LayoutWidgetType.Unknown) return; if (widget.AllTypes.All (wt => wt == LayoutWidgetType.View)) widget.WidgetType = LayoutWidgetType.View; else if (widget.AllTypes.All (wt => wt == LayoutWidgetType.Fragment)) widget.WidgetType = LayoutWidgetType.Fragment; else widget.WidgetType = LayoutWidgetType.Mixed; }
public void WriteBindingProperty(State state, LayoutWidget widget, string resourceNamespace) { EnsureArgument(state, nameof(state)); EnsureArgument(widget, nameof(widget)); state.WriteLine(); WriteBindingPropertyBackingField(state, widget); state.WriteLine(); WriteLocationDirective(state, widget); foreach (LayoutLocationInfo loc in widget.Locations) { if (loc == null) { continue; } WriteComment(state, $" Declared in: {loc.FilePath}:({loc.Line}:{loc.Column})"); } if (widget.TypeFixups != null) { foreach (LayoutTypeFixup tf in widget.TypeFixups) { WriteComment(state, $" Type fixed up from '{tf.OldType}' to '{widget.Type}'. Element defined in {tf.Location.FilePath}:({tf.Location.Line}:{tf.Location.Column})"); } } switch (widget.WidgetType) { case LayoutWidgetType.View: WriteBindingViewProperty(state, widget, resourceNamespace); break; case LayoutWidgetType.Fragment: WriteBindingFragmentProperty(state, widget, resourceNamespace); break; case LayoutWidgetType.Mixed: WriteBindingMixedProperty(state, widget, resourceNamespace); break; case LayoutWidgetType.Unknown: throw new InvalidOperationException($"Widget must have a known type (ID: {widget.Id})"); default: throw new InvalidOperationException($"Unsupported widget type '{widget.WidgetType}' (ID: {widget.Id})"); } WriteResetLocation(state); state.WriteLine(); }
bool NameMatchesBindingClass(State state, LayoutWidget widget, StringComparison comparison) { if (String.IsNullOrEmpty(state.BindingClassName)) { return(false); } int dot = state.BindingClassName.LastIndexOf('.'); if (dot < 0) { return(false); } return(String.Compare(state.BindingClassName.Substring(dot + 1), widget.Name, comparison) == 0); }
protected string GetWidgetId(LayoutWidget widget, out bool isGlobal) { if (String.IsNullOrEmpty(widget?.Id)) { isGlobal = false; return(String.Empty); } isGlobal = widget.Id.StartsWith(CalculateLayoutCodeBehind.GlobalIdPrefix, StringComparison.Ordinal); if (!isGlobal) { return(widget.Id); } return(widget.Id.Substring(CalculateLayoutCodeBehind.GlobalIdPrefix.Length)); }
protected override void WriteLocationDirective(State state, LayoutWidget widget) { EnsureArgument(state, nameof(state)); EnsureArgument(widget, nameof(widget)); // There might be several locations, we will write only the first one since we can have // only one and first is as good as any LayoutLocationInfo loc = widget.Locations?.FirstOrDefault(); if (loc == null) { return; } WriteLineIndent(state, $"#line {loc.Line} \"{loc.FilePath}\""); state.WriteLine(); }
protected virtual string GetValidPropertyName(State state, LayoutWidget widget) { EnsureArgument(state, nameof(state)); EnsureArgument(state, nameof(widget)); // It is possible that a widget/element will have the same ID as the name of the // encompassing layout. In this case we mustn't use the ID of the widget directly // because a class cannot have members (other than constructors) with named the same as // the enclosing type. We could rename the generated class but that still doesn't // guarantee the lack of naming conflicts (e.g. if we append `Layout` to the class name, // there may still be a widget with the same ID). It is better to append a suffix to the // property name since we're guaranteed that each property is unique. StringComparison comparison = CaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase; if (String.Compare(state.ClassName, widget.Name, comparison) != 0 && !NameMatchesBindingClass(state, widget, comparison)) { return(widget.Name); } string suffix = null; switch (widget.WidgetType) { case LayoutWidgetType.View: suffix = "View"; break; case LayoutWidgetType.Fragment: suffix = "Fragment"; break; case LayoutWidgetType.Mixed: suffix = "Object"; break; case LayoutWidgetType.Unknown: throw new InvalidOperationException($"Widget must have a known type (ID: {widget.Id})"); default: throw new InvalidOperationException($"Unsupported widget type '{widget.WidgetType}' (ID: {widget.Id})"); } return($"{widget.Name}_{suffix}"); }
protected override void WriteBindingMixedProperty(State state, LayoutWidget widget, string resourceNamespace) { EnsureArgument(state, nameof(state)); EnsureArgument(widget, nameof(widget)); WritePropertyDeclaration(state, widget, false); state.IncreaseIndent(); WriteLineIndent(state, "get {"); state.IncreaseIndent(); WriteIndent(state, "object ret = "); WriteBindingFinderCall(state, widget, resourceNamespace, "FindView"); state.WriteLine(";"); WriteLineIndent(state, "if (ret != null) return ret;"); WriteIndent(state, "return "); WriteBindingFinderCall(state, widget, resourceNamespace, "FindFragment", true); state.WriteLine(";"); state.DecreaseIndent(); WriteLineIndent(state, "}"); state.DecreaseIndent(); WriteLineIndent(state, "}"); }
void WriteBindingFinderCall(State state, LayoutWidget widget, string resourceNamespace, string finderMethodName, bool isFragment = false) { bool isIdGlobal; string id = GetWidgetId(widget, out isIdGlobal); if (!isIdGlobal) { id = $"{resourceNamespace}{id}"; } string backingFieldName = GetBindingBackingFieldName(widget); string extraParam; if (isFragment) { extraParam = $" {backingFieldName},"; } else { extraParam = null; } state.Write($"{finderMethodName} (global::{id},{extraParam} ref {backingFieldName})"); }
public override void WritePartialClassProperty(State state, LayoutWidget widget) { WritePropertyDeclaration(state, widget, true); state.WriteLine($"{BindingPartialClassBackingFieldName}?.{GetValidPropertyName (state, widget)};"); }
void WriteBindingLambdaPropertyGetter(State state, LayoutWidget widget, string resourceNamespace, string finderMethodName, bool isFragment = false) { WritePropertyDeclaration(state, widget, true); WriteBindingFinderCall(state, widget, resourceNamespace, finderMethodName, isFragment); state.WriteLine(";"); }
void CreateWidget(XPathNavigator current, string filePath, string androidNS, string xamarinNS, string id, string parsedId, string name, string partialClasses, ref IDictionary <string, LayoutWidget> widgets) { bool isFragment = String.Compare("fragment", current.LocalName, StringComparison.Ordinal) == 0; string managedType = current.GetAttribute(XamarinManagedTypeAttribute, xamarinNS); string oldType = null; if (String.IsNullOrEmpty(managedType)) { bool mayNeedTypeFixup = true; if (isFragment) { managedType = current.GetAttribute("name", androidNS)?.Trim(); if (String.IsNullOrEmpty(managedType)) { mayNeedTypeFixup = false; managedType = "global::Android.App.Fragment"; } } else { managedType = current.LocalName; } if (mayNeedTypeFixup) { mayNeedTypeFixup = !FixUpTypeName(ref managedType); } int idx = managedType.IndexOf(','); if (idx >= 0) { managedType = managedType.Substring(0, idx).Trim(); } if (mayNeedTypeFixup && (idx = managedType.LastIndexOf('.')) >= 0) { LogCodedWarning("XA1005", $"Attempting naive type name fixup for element with ID '{id}' and type '{managedType}'"); LogCodedWarning("XA1005", "If the above fixup fails, please add `xamarin:managedType` attribute to the element with fully qualified managed type name of the element"); oldType = managedType; string ns = managedType.Substring(0, idx); string klass = managedType.Substring(idx + 1); string fixedNS = null; if (FixUpNamespace(ns, out fixedNS)) { LogMessage($"Fixed up a known namespace from '{ns}' to '{fixedNS}'"); managedType = $"{fixedNS}.{klass}"; } else { LogMessage("Fixed up namespace by naive capitalization of the name"); managedType = $"{CapitalizeName (ns)}.{klass}"; } LogMessage($"Element with ID '{id}' managed type fixed up to: '{managedType}'"); } } LayoutWidget widget; bool fresh = false; if (!widgets.TryGetValue(parsedId, out widget) || widget == null) { fresh = true; widget = new LayoutWidget { Id = parsedId, Type = managedType, Name = name, PartialClasses = partialClasses, AllTypes = new List <LayoutWidgetType> (), Locations = new List <LayoutLocationInfo> (), WidgetType = isFragment ? LayoutWidgetType.Fragment : LayoutWidgetType.View, }; widgets [widget.Id] = widget; } LayoutLocationInfo location = GetLocationInfo(current, filePath); widget.AllTypes.Add(widget.WidgetType); widget.Locations.Add(location); if (oldType != null) { if (widget.TypeFixups == null) { widget.TypeFixups = new List <LayoutTypeFixup> (); } widget.TypeFixups.Add(new LayoutTypeFixup { OldType = oldType, Location = location }); } if (fresh) { return; } if (widget.Type != null && String.Compare(widget.Type, managedType, StringComparison.Ordinal) == 0) { return; } widget.Type = null; widget.WidgetType = LayoutWidgetType.Unknown; widget.AllTypes.Add(isFragment ? LayoutWidgetType.Fragment : LayoutWidgetType.View); }
void WriteBindingFinderCall(State state, LayoutWidget widget, string resourceNamespace, string finderMethodName) { state.Write($"{finderMethodName} (global::{resourceNamespace}{widget.Id}, ref {GetBindingBackingFieldName (widget)})"); }
public abstract void WritePartialClassProperty(State state, LayoutWidget widget);
protected override string GetBindingPropertyBackingField(State state, LayoutWidget widget) { EnsureArgument(widget, nameof(widget)); return($"{widget.Type} {GetBindingBackingFieldName (widget)};"); }
protected abstract void WriteBindingMixedProperty(State state, LayoutWidget widget, string resourceNamespace);
protected abstract void WriteLocationDirective(State state, LayoutWidget widget);
protected string GetWidgetId(LayoutWidget widget) { return(GetWidgetId(widget, out _)); }
protected virtual string GetBindingBackingFieldName(LayoutWidget widget) { return($"__{widget.Name}"); }
protected abstract string GetBindingPropertyBackingField(LayoutWidget widget);