/// <summary> /// Apply the specified attributes to the XmlElement (and its other relevant components) /// </summary> /// <param name="attributesToApply"></param> public virtual void ApplyAttributes(AttributeDictionary attributesToApply) { if (currentInstanceTransform == null || currentXmlLayoutInstance == null) { Debug.LogWarning("[XmlLayout][Warning] Please call ElementTagHandler.SetInstance() before using XmlElement.ApplyAttributes()"); return; } //var startTime = DateTime.Now; attributesToApply = HandleCustomAttributes(attributesToApply); var _primaryComponent = primaryComponent; // the vast majority of events require the element to block raycasts, so rather than expecting the users to set this value every time, // lets set it here if (attributesToApply.Any(a => !String.Equals("onValueChanged", a.Key, StringComparison.OrdinalIgnoreCase) && eventAttributeNames.Contains(a.Key, StringComparer.OrdinalIgnoreCase))) { attributesToApply.AddIfKeyNotExists("raycastTarget", "true"); } else if (!String.IsNullOrEmpty(attributesToApply.GetValue("tooltip"))) { attributesToApply.AddIfKeyNotExists("raycastTarget", "true"); } if (attributesToApply.ContainsKey("allowDragging") && attributesToApply["allowDragging"].ToBoolean()) { var dragEventHandler = currentXmlElement.GetComponent <XmlLayoutDragEventHandler>(); if (dragEventHandler == null) { currentXmlElement.gameObject.AddComponent <XmlLayoutDragEventHandler>(); } } foreach (var attribute in attributesToApply) { string name = attribute.Key.ToLower(); string value = attribute.Value; if (eventAttributeNames.Contains(name, StringComparer.OrdinalIgnoreCase)) { // As it happens, events don't work anyway unless they are processed at runtime (which is why we have 'ForceRebuildOnAwake') // so we may as well not process any event attributes at all in edit mode // (this also helps avoid triggering event handlers in edit mode) // Note: we set these at the end of the frame so that any internal event-handlers (such as for MVVM) will take precedence // and be executed first var _xmlLayoutInstance = currentXmlLayoutInstance; var _transform = currentInstanceTransform; if (Application.isPlaying) { XmlLayoutTimer.AtEndOfFrame(() => { if (_transform == null || _xmlLayoutInstance == null) { return; } SetInstance(_transform, _xmlLayoutInstance); HandleEventAttribute(name, value); }, null, true); } continue; } var propertySetOnComponent = _primaryComponent != null?SetPropertyValue(_primaryComponent, name, value) : false; // if we failed to set the property on the component, perhaps it is a transform value instead if (!propertySetOnComponent) { var propertySetOnTransform = SetPropertyValue(currentInstanceTransform, name, value); // perhaps it is a layout value if (!propertySetOnTransform) { var propertySetOnLayoutComponent = SetPropertyValue(layoutElement, name, value); // or, perhaps it is an image value if (!propertySetOnLayoutComponent) { // lastly, check the XmlElement var propertySetOnXmlElement = SetPropertyValue(currentXmlElement, name, value); if (!propertySetOnXmlElement) { var _imageComponent = imageComponent; if (_imageComponent != null) { SetPropertyValue(imageComponent, name, value); } } } } } } #if !ENABLE_IL2CPP && MVVM_ENABLED if (!dontCallHandleDataSourceAttributeAutomatically && attributesToApply.ContainsKey("vm-dataSource")) { HandleDataSourceAttribute(attributesToApply["vm-dataSource"]); } // If this element is associated with a data source, but has no vm-dataSource attribute // (perhaps it was removed) // then remove the association if (!currentXmlElement.attributes.ContainsKey("vm-dataSource")) { currentXmlLayoutInstance.ElementDataSources.RemoveAll(ed => ed.XmlElement == currentXmlElement); } #endif }
protected void ClassRemoved(params string[] classesRemoved) { if (!xmlLayout.defaultAttributeValues.ContainsKey(this.tagType)) { return; } List <string> attributesReset = new List <string>(); foreach (var classRemoved in classesRemoved) { if (!xmlLayout.defaultAttributeValues[this.tagType].ContainsKey(classRemoved)) { continue; } var attributesDefinedByClass = xmlLayout.defaultAttributeValues[this.tagType][classRemoved].Select(a => a.Key).ToList(); // add all attributes defined by this class that are not defined by the element attributesReset.AddRange(attributesDefinedByClass.Where(a => !elementAttributes.Contains(a))); } if (!attributesReset.Any()) { return; } var _classes = classes; _classes.Insert(0, "all"); // remove any attributes covered by other classes (no need to reset them) foreach (var _class in _classes) { if (!xmlLayout.defaultAttributeValues[this.tagType].ContainsKey(_class)) { continue; } var attributesDefinedByClass = xmlLayout.defaultAttributeValues[this.tagType][_class].Select(a => a.Key).ToList(); attributesReset.RemoveAll(a => attributesDefinedByClass.Contains(a)); } if (attributesReset.Any()) { // Now for the hard part: we need to determine the default values for these attributes AttributeDictionary defaultAttributesToApply = new AttributeDictionary(); foreach (var attributeToReset in attributesReset) { var value = tagHandler.GetDefaultValueForAttribute(attributeToReset); defaultAttributesToApply.Add(attributeToReset, value); } if (defaultAttributesToApply.Any()) { ApplyAttributes(defaultAttributesToApply); } } }
/// <summary> /// Apply the specified attributes to the XmlElement (and its other relevant components) /// </summary> /// <param name="attributesToApply"></param> public virtual void ApplyAttributes(AttributeDictionary attributesToApply) { if (currentInstanceTransform == null || currentXmlLayoutInstance == null) { Debug.LogWarning("[XmlLayout][Warning] Please call ElementTagHandler.SetInstance() before using XmlElement.ApplyAttributes()"); return; } //var startTime = DateTime.Now; attributesToApply = HandleCustomAttributes(attributesToApply); var _primaryComponent = primaryComponent; // the vast majority of events require the element to block raycasts, so rather than expecting the users to set this value every time, // lets set it here if (attributesToApply.Any(a => !String.Equals("onValueChanged", a.Key, StringComparison.OrdinalIgnoreCase) && eventAttributeNames.Contains(a.Key, StringComparer.OrdinalIgnoreCase))) { attributesToApply.AddIfKeyNotExists("raycastTarget", "true"); } if (attributesToApply.ContainsKey("allowDragging") && attributesToApply["allowDragging"].ToBoolean()) { var dragEventHandler = currentXmlElement.GetComponent <XmlLayoutDragEventHandler>(); if (dragEventHandler == null) { currentXmlElement.gameObject.AddComponent <XmlLayoutDragEventHandler>(); } } foreach (var attribute in attributesToApply) { string name = attribute.Key; string value = attribute.Value; if (eventAttributeNames.Contains(name, StringComparer.OrdinalIgnoreCase)) { // As it happens, events don't work anyway unless they are processed at runtime (which is why we have 'ForceRebuildOnAwake') // so we may as well not process any event attributes at all in edit mode // (this also helps avoid triggering event handlers in edit mode) if (Application.isPlaying) { HandleEventAttribute(name, value); } continue; } var propertySetOnComponent = _primaryComponent != null?SetPropertyValue(_primaryComponent, name, value) : false; // if we failed to set the property on the component, perhaps it is a transform value instead if (!propertySetOnComponent) { var propertySetOnTransform = SetPropertyValue(currentInstanceTransform, name, value); // perhaps it is a layout value if (!propertySetOnTransform) { var propertySetOnLayoutComponent = SetPropertyValue(layoutElement, name, value); // or, perhaps it is an image value if (!propertySetOnLayoutComponent) { // lastly, check the XmlElement var propertySetOnXmlElement = SetPropertyValue(currentXmlElement, name, value); if (!propertySetOnXmlElement) { var _imageComponent = imageComponent; if (_imageComponent != null) { SetPropertyValue(imageComponent, name, value); } } } } } } #if !ENABLE_IL2CPP if (!dontCallHandleDataSourceAttributeAutomatically && attributesToApply.ContainsKey("vm-dataSource")) { HandleDataSourceAttribute(attributesToApply["vm-dataSource"]); } #endif }