A rule marked as External has special behavior during unbind. When an External rule slot is unbound, an UnboundSlot object is added to a collection. At the end of an unbind cycle, an UnbindNotifyEvent event is fired with the collection in an argument. When the event handler(s) complete, the collection is cleared.
The UnbindNotifyEvent handler should inspect the collection for slots of interest and appropriately manage the destruction of the slot value or merely take action based on the notification that the slot has been unbound. The collection may contain entries for system or 3rd party slots, so don't assume that all unbound slots need to be handled. Note that unbinding does not imply rebinding. An unbound slot may never get re‐bound, due to parameter changes. The handler should be very careful with evaluation or other Intent API calls during this event; it is possible that another event could trigger. It is recommended that no action take place at this time, just collection of relevant information to be applied after the event completes.
In Intent source, the values of External rules should be carefully treated. Copying such values into other rules could result in stale object handles. The unbinding of dependent values may alleviate some of this problem, but it must be considered. For example:
External Rule Foo as User = getMyData(42) Rule Foo2 as User = Foo Rule Foo3 As User = getMyData(42)
When Foo is unbound, Foo2 will be unbound as well, so this copy is “safe”. But if getMyObject(42) always returns the same object, and your response to unbinding is to destroy that object, then Foo3 will have a stale reference, and potential problems arise. These examples are extremely simplified; much more complex situations are possible which can be difficult to recognize.
The argument in the event is an instance of UnbindNotifyEventArgs, which contains a reference to the single, global current UnboundSlotCollection. An UnboundSlot contains a reference chain for the slot, and the value that was unbound. The value has not been otherwise altered by Intent. The handler can identify their External slots by name or value. Since all External rules that were unbound will be in the event collection, it is important to only process those which were created by you. Names should be chosen to be unique; if this is not possible, then the unbound value should be inspected to ensure that the data contained is yours.
What is an unbind cycle? An unbind is triggered by anything that invalidates the data in a slot. Most unbinds are in fact the result of a dependee slot being unbound. The UnbindNotifyEvent is not triggered at every unbind, but instead it is fired at the conclusion of a series of recursive unbinds. The collection is empty at the start of the “root” of the unbinding recursion, and may contain External unbound slots at the end. If the collection is still empty, no event is fired.
It is often the case that an application will want to do a series of operations that will trigger many unbind cycles, and handle a single event at the end. The collection is still processed normally, but the event is suppressed. This is controlled with the IsUnboundNotifyEnabled property of ModelEvents. The default value is True . If set to False , the UnbindNotifyEvent is suppressed, but the collection keeps going. As soon as it is set to True , the event is fired (assuming the collection is not empty, it will never fire if empty).
Design INT_817 : BasePart External Parameter Rule Ex1 As Integer = 42 Rule DependsOnEx1 As Integer = Floor(Ex1 / 2) End Design
// Test of UnbindNotifyEvent ModelEvents modelEvents = ModelEvents.Instance; modelEvents.UnbindNotify += UnbindNotifyHandler; Application.Run(new MainWindow(UIMode)); modelEvents.UnbindNotify ‐= UnbindNotifyHandler;The event handler for the simple message box:
private static void UnbindNotifyHandler(Object sender, UnbindNotifyEventArgs args) { System.Text.StringBuilder sb = new System.Text.StringBuilder("Slot Refchain\tValue\n"); foreach (UnboundSlot us in args.SlotCollection) { sb.Append(us.RefChain.AsString + "\t" + us.Value + "\n"); } MessageBox.Show(sb.ToString(),"UnbindNotifyEvent"); }