/// <summary>
        /// Defines a new RootStateEventListener with the given state being considered
        /// the "root" state, relative to which all properties will be resolved and which
        /// will be listened for.
        /// </summary>
        /// <param name="root">The root state. All events and properties will be relative
        /// to the root state.</param>
        /// <exception cref="ArgumentNullException">The passed state was null.</exception>
        public RootStateEventListener(ChangeableState root)
        {
            this.root = root;
            if (this.root == null)
            {
                throw new ArgumentNullException(nameof(root));
            }

            this.tree = new PropertyNameTree();
            this.root.PropertyChanged += OnRootPropertyChanged;
        }
Пример #2
0
        private void OnPropertyChanged(string propertyName, object newValue)
        {
            bool lockTaken  = false;
            bool iAmEntrant = false;

            try
            {
                Monitor.Enter(_stateLock, ref lockTaken);

                if (reentrant)
                {
                    return;            // prevent re-entry from substate update => prevents infinite loops
                }
                reentrant = iAmEntrant = true;

                bool shouldUpdateSubstate = newValue is ChangeableState && ShouldUpdatePropertyAsSubstate(propertyName);
                if (_substates.ContainsKey(propertyName)) // discard old substate regardless
                {
                    SubstateListener substate = _substates[propertyName];
                    substate.State.PropertyChanged -= substate.Handler;
                    _substates.Remove(propertyName);
                }

                if (_pausedStateDirtySet != null) // paused?
                {
                    _pausedStateDirtySet[propertyName] = newValue;
                    return;
                }

                if (shouldUpdateSubstate)
                {
                    ChangeableState            newSubstate = (ChangeableState)newValue;
                    PropertyChangeEventHandler newHandler  = (object sender, PropertyChangeEventArgs e) =>
                    {
                        this.OnPropertyChanged(propertyName + "." + e.PropertyName, e.NewValue);
                    };
                    _substates[propertyName]     = new SubstateListener(newSubstate, newHandler);
                    newSubstate.PropertyChanged += newHandler;
                }
                PropertyChanged?.Invoke(this, new PropertyChangeEventArgs(propertyName, newValue));
            }
            finally
            {
                reentrant &= !iAmEntrant;
                if (lockTaken)
                {
                    Monitor.Exit(_stateLock);
                }
            }
        }
Пример #3
0
 public SubstateListener(ChangeableState state, PropertyChangeEventHandler handler)
 {
     State   = state;
     Handler = handler;
 }