/// <summary> /// Dynamically generate repeat items, reusing existing instances if available. /// </summary> /// <returns></returns> public void Update() { // refresh binding if (Binding != null) { Binding.Recalculate(); } // configure listener for instance alterations if (Binding != null && Binding.Context != null) { if (listener == null) { var target = Binding.Context.Instance.Element.Parent.Interface <EventTarget>(); // find existing listener listener = InterfaceEventListener.GetListener(target, Events.Insert, true, Update) ?? InterfaceEventListener.GetListener(target, Events.Delete, true, Update); // register listener if (listener == null) { listener = InterfaceEventListener.Create(Update); target.Register(Events.Insert, listener, true); target.Register(Events.Delete, listener, true); } } } // store current index item var indexPrev = Index; var indexItem = Element .Elements() .FirstOrDefault(i => i.AnnotationOrCreate <RepeatItemState>().Index == Index); // build new list of properly ordered nodes var items = Binding != null?Binding.ModelItems.Select(i => i.Xml).ToArray() : new XObject[0]; var nodes = Element.Elements().ToArray(); var sorts = new XElement[items.Length]; for (int index = 0; index < items.Length; index++) { // model item at current index var item = items[index]; // get existing item or create new var indx = Array.FindIndex(nodes, i => i.AnnotationOrCreate <RepeatItemState>().ModelObjectId == item.GetObjectId()); var node = indx >= 0 ? nodes[indx] : null; if (node == null) { node = new XElement( Constants.XForms_1_0 + "group", Template.GetNamespacePrefixAttributes(), Template.Nodes()); } // set node into output list sorts[index] = node; // configure item state var anno = node.AnnotationOrCreate <RepeatItemState>(); anno.ModelObjectId = item.GetObjectId(); anno.Index = index + 1; anno.Size = items.Length; } // new sequence is different from old sequence if (sorts.Length != nodes.Length || sorts.SequenceEqual(nodes) == false) { // replace all children Element.RemoveNodes(); Element.Add(sorts); // set of elements that were added var added = sorts .Except(nodes) .ToArray(); // model-construct-done sequence applied to new children foreach (var node in added) { foreach (var i in GetAllExtensions <IOnRefresh>(node)) { i.RefreshBinding(); } } // discard refresh events foreach (var node in added) { foreach (var i in GetAllExtensions <IOnRefresh>(node)) { i.DiscardEvents(); } } // final refresh foreach (var node in added) { foreach (var i in GetAllExtensions <IOnRefresh>(node)) { i.Refresh(); } } } // restore or reset index var length = Element.Elements().Count(); if (indexItem != null && indexItem.Parent != null) { Index = indexItem.AnnotationOrCreate <RepeatItemState>().Index; } else if (indexPrev > 0) { Index = indexPrev <= length ? indexPrev : length; } else if (length > 0) { Index = 1; } else { Index = 0; } }
/// <summary> /// Refreshes all properties. /// </summary> public void Refresh() { var oldItemType = DataType; var oldRelevant = Relevant; var oldReadOnly = ReadOnly; var oldRequired = Required; var oldValid = Valid; var oldValue = Value; if (binding != null) { binding.Recalculate(); if (modelItem != binding.ModelItem) { modelItem = binding.ModelItem; } } if (modelItem != null) { State.DataType = modelItem.ItemType; State.Relevant = modelItem.Relevant; State.ReadOnly = modelItem.ReadOnly; State.Required = modelItem.Required; State.Valid = modelItem.Valid; State.Value = modelItem.Value; } else { // default values State.DataType = null; State.Relevant = true; State.ReadOnly = false; State.Required = false; State.Valid = true; State.Value = null; } // mark all required events var valueChanged = Value != oldValue; if (valueChanged) { State.DispatchValueChanged = true; } if (Relevant != oldRelevant || valueChanged) { if (Relevant) { State.DispatchEnabled = true; } else { State.DispatchDisabled = true; } } if (ReadOnly != oldReadOnly || valueChanged) { if (ReadOnly) { State.DispatchReadOnly = true; } else { State.DispatchReadWrite = true; } } if (Required != oldRequired || valueChanged) { if (Required) { State.DispatchRequired = true; } else { State.DispatchOptional = true; } } if (Valid != oldValid || valueChanged) { if (Valid) { State.DispatchValid = true; } else { State.DispatchInvalid = true; } } }