using System; using JD.Kernel.Classes; using JD.Kernel.StaticHelpers; namespace JD.PropertyService { /// /// Properties that cache changes made to them until they are bulk written to /// the property object which is being cached. /// public class TransactionalProperties : Properties, IDisposable { #region Variables private readonly Scope m_isSyncing = new Scope(); private IProperties m_internalProperties; private bool m_isDirty; #endregion #region Constructor /// /// Constructor /// public TransactionalProperties() : this(new Properties()) {} /// /// Constructor /// /// public TransactionalProperties(IProperties cachedProperties) { Throw.IfNull(cachedProperties, "cachedProperties"); InternalProperties = cachedProperties; } #endregion #region Properties /// /// Dirty flag /// public bool IsDirty { get { return m_isDirty; } } public override bool IsReadOnly { get { return m_internalProperties.IsReadOnly; } } /// /// Access to the cached properties /// public IProperties InternalProperties { get { return m_internalProperties; } set { if (m_internalProperties != null) { m_internalProperties.PropertyChanged -= InternalPropertiesPropertyChanged; } m_internalProperties = value; if (m_internalProperties != null) { m_internalProperties.PropertyChanged += InternalPropertiesPropertyChanged; Revert(); } } } private bool Syncing { get { return m_isSyncing.InScope; } } #endregion #region Public Methods /// /// Write dirty cache entries to cached properties, then reload the cache. /// public void Commit() { if (!Syncing) { using (m_isSyncing.Begin()) { if (m_isDirty && OnPropertyChanging()) { using (m_internalProperties.BeginScopedUpdate()) { m_internalProperties.Clear(); CopyTo(m_internalProperties); } m_isDirty = false; OnCommit(); } } } } /// /// Load the cache from the properties being cached, discarding any previous cache content. /// public void Revert() { if (!Syncing) { using (m_isSyncing.Begin()) { Clear(); m_internalProperties.CopyTo(this); m_isDirty = false; OnReverted(); } } } #endregion #region Events private void OnCommit() { Commited?.Invoke(this, EventArgs.Empty); } private void OnReverted() { Reverted?.Invoke(this, EventArgs.Empty); } /// /// Raised when the cache has been reloaded from the cached item. /// public event EventHandler Reverted; /// /// Raised when a dirty cache was written. /// public event EventHandler Commited; #endregion #region Event Handlers protected override void OnPropertyChanged(PropertyChangedEventArgs e) { m_isDirty = true; base.OnPropertyChanged(e); } private void InternalPropertiesPropertyChanged(object sender, PropertyChangedEventArgs e) { Revert(); } #endregion #region IDisposable Members /// /// Interface implementation /// public void Dispose() { // unbind event handlers InternalProperties = null; } #endregion } }