/// <summary> /// Reads this Item's value from it's source and, if the read value is different from the present value of the /// <see cref="Value"/> property, updates the Value and fires the <see cref="Changed"/> event by invoking the /// <see cref="Write"/> method and passing the read value. /// </summary> /// <remarks> /// If the <see cref="ItemSource"/> of the Item is <see cref="ItemSource.Item"/>, the value is retrieved from the /// <see cref="ReadFromSource"/> method of the <see cref="SourceItem"/>. If the ItemSource is /// <see cref="ItemSource.Provider"/>, the value is retrieved from the <see cref="Provider"/> object's /// <see cref="IItemProvider.Read(Item)"/> method. If the ItemSource is <see cref="ItemSource.Unknown"/>, the present /// value of the <see cref="Value"/> property is returned. If the ItemSource is <see cref="ItemSource.Unresolved"/>, a /// null value is returned. /// </remarks> /// <returns>The retrieved value.</returns> /// <threadsafety instance="true"/> public virtual object ReadFromSource() { // recursively call ReadFromSource() on each child in this Item's children collection this allows us to update whole // branches of the model with a single read if (HasChildren) { IList <Item> children; childrenLock.EnterReadLock(); try { children = Children; } finally { childrenLock.ExitReadLock(); } foreach (Item child in Children) { child.ReadFromSource(); } } // prepare a variable to hold the read result object value = new object(); ItemQuality quality = ItemQuality.Good; // if the source is an Item, return the result from that Item's ReadFromSource() method. This will recursively refresh // each Item in the chain until the last Item (that which the Source = ItemProvider) is refreshed directly from the source. if (Source == ItemSource.Item) { sourceItemLock.EnterReadLock(); try { value = SourceItem.ReadFromSource(); } finally { sourceItemLock.ExitReadLock(); } } else if (Source == ItemSource.Provider) { // if the source of this Item is an ItemProvider and it implements IReadable, return the value of the Read() method // for the provider. this will be the final read in the chain. providerLock.EnterReadLock(); try { value = Provider.Read(this); } catch (Exception) { value = null; quality = ItemQuality.Bad; } finally { providerLock.ExitReadLock(); } } else if (Source == ItemSource.Unknown) { // if the source of this Item is unknown, the authoritative source for the Item's value is itself, so return the // Value property. valueLock.EnterReadLock(); try { value = Value; } finally { valueLock.ExitReadLock(); } } else if (Source == ItemSource.Unresolved) { // if the source of this Item is an unresolved FQN, return null. value = null; quality = ItemQuality.Bad; } ChangeValue(value, quality); return(Read()); }