예제 #1
0
            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);
 }
예제 #3
0
 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);
            }
예제 #7
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));
            }
예제 #8
0
            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}");
            }
예제 #10
0
            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, "}");
            }
예제 #11
0
            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})");
            }
예제 #12
0
 public override void WritePartialClassProperty(State state, LayoutWidget widget)
 {
     WritePropertyDeclaration(state, widget, true);
     state.WriteLine($"{BindingPartialClassBackingFieldName}?.{GetValidPropertyName (state, widget)};");
 }
예제 #13
0
 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(";");
 }
예제 #14
0
        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);
예제 #17
0
 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);
예제 #20
0
 protected string GetWidgetId(LayoutWidget widget)
 {
     return(GetWidgetId(widget, out _));
 }
 protected virtual string GetBindingBackingFieldName(LayoutWidget widget)
 {
     return($"__{widget.Name}");
 }
 protected abstract string GetBindingPropertyBackingField(LayoutWidget widget);