internal PropertyData(object defaultValue, Type type, PropertyChangedCallbackHandler propertyChangedCallback)
            {
                Value = defaultValue;
                Type  = type;

                PropertyChangedCallback += propertyChangedCallback;
            }
        /// <summary>
        /// Registers a new property in the actual instance of <see cref="NotifyPropertyChanged"/>.
        /// </summary>
        /// <param name="name">Name of the registered property.</param>
        /// <param name="type">Type of the registered property.</param>
        /// <param name="defaultValue">Default value of the registered property.</param>
        /// <param name="propertyChangedCallback">Callback invoked right after the registered property changes.</param>
        /// <exception cref="ArgumentException">
        ///     <para>
        ///         Parameter <paramref name="name"/> is <c>null</c> or white space.
        ///     </para>
        ///     <para>
        ///         Value of <paramref name="defaultValue"/> cannot be assigned to a property of type specified in the <paramref name="type"/> parameter.
        ///     </para>
        ///     <para>
        ///         Instance already contains a registered property named the same as specified in parameter <paramref name="name"/>.
        ///     </para>
        /// </exception>
        /// <exception cref="ArgumentNullException">Parameter <paramref name="type"/> is <c>null</c>.</exception>
        protected void RegisterProperty(string name, Type type, object defaultValue, PropertyChangedCallbackHandler propertyChangedCallback)
        {
            Helpers.ValidateStringNotNullOrWhiteSpace(name, nameof(name));
            Helpers.ValidateObjectNotNull(type, nameof(type));
            ValidateValueForType(defaultValue, type);

            if (backingStore.ContainsKey(name))
            {
                throw new ArgumentException($"This class already contains registered property named '{name}'.");
            }

            backingStore.Add(name, new PropertyData(defaultValue, type, propertyChangedCallback));
        }
        public void WorkingWithPropertiesTest()
        {
            Wrapper w = new Wrapper();

            // Invalid property name
            AllThrows <string, ArgumentException>(invalidPropertyNames, invalidPropertyName => w.GetValue(invalidPropertyName));
            AllThrows <string, ArgumentException>(invalidPropertyNames, invalidPropertyName => w.SetValue(null, invalidPropertyName));
            AllThrows <string, ArgumentException>(invalidPropertyNames, invalidPropertyName => w.ForceSetValue(null, invalidPropertyName));

            // Not registered property
            Assert.ThrowsException <ArgumentException>(() => w.GetValue("NotRegisteredProperty"));
            Assert.ThrowsException <ArgumentException>(() => w.SetValue(null, "NotRegisteredProperty"));
            Assert.ThrowsException <ArgumentException>(() => w.ForceSetValue(null, "NotRegisteredProperty"));

            int    propertyChangedEventInvokeCount    = 0;
            int    propertyChangedCallbackInvokeCount = 0;
            bool   propertyChangedCallbackRegistered  = true;
            string propertyName = null;
            object oldValue     = null;
            object value        = null;

            w.PropertyChanged += (sender, e) =>
            {
                Assert.AreEqual(w, sender);
                Assert.AreEqual(propertyName, e.PropertyName);

                propertyChangedEventInvokeCount++;
            };
            PropertyChangedCallbackHandler propertyChangedCallback = (sender, e) =>
            {
                Assert.AreEqual(w, sender);
                Assert.IsFalse(e.Handled);
                Assert.AreEqual(oldValue, e.OldValue);
                Assert.AreEqual(value, e.NewValue);

                propertyChangedCallbackInvokeCount++;
            };

            foreach (TypeData typeData in typeDataCollection)
            {
                for (int i = 0; i < typeData.DefaultValues.Length; i++)
                {
                    object defaultValue = typeData.DefaultValues[i];

                    propertyName = typeData.Type.Name + i;
                    Test(false, true, defaultValue);
                    propertyName += "_Forced";
                    Test(true, true, defaultValue);

                    propertyName = typeData.Type.Name + i + "_NoPropertyChangedEvent";
                    Test(false, false, defaultValue);
                    propertyName += "_Forced";
                    Test(true, false, defaultValue);
                }

                // Invalid value
                AllThrows <object, ArgumentException>(typeData.InvalidValues, invalidValue => w.SetValue(invalidValue, propertyName));
                AllThrows <object, ArgumentException>(typeData.InvalidValues, invalidValue => w.ForceSetValue(invalidValue, propertyName));

                void Test(bool force, bool eventsEnabled, object defaultValue)
                {
                    w.IsPropertyChangedEventInvokingEnabled    = eventsEnabled;
                    w.IsPropertyChangedCallbackInvokingEnabled = eventsEnabled;
                    propertyChangedCallbackRegistered          = true;

                    oldValue = null;
                    value    = defaultValue;

                    // Default value
                    w.RegisterProperty(propertyName, typeData.Type, value, propertyChangedCallback);
                    Assert.AreEqual(value, w.GetValue(propertyName));
                    CheckEventsInvoked(false);

                    CheckNoChangeSet();

                    propertyChangedCallbackRegistered = false;
                    w.UnregisterPropertyChangedCallback(propertyName, propertyChangedCallback);

                    // Changing value but not assigning it to property
                    SetValue(typeData.GetNewValue(value));
                    // Probably not needed but I like this ( ͡° ͜ʖ ͡°)
                    Assert.AreNotEqual(value, w.GetValue(propertyName));
                    CheckEventsInvoked(false);

                    // Assigning changed value
                    SetAndTest(eventsEnabled);

                    CheckNoChangeSet();

                    w.RegisterPropertyChangedCallback(propertyName, propertyChangedCallback);
                    propertyChangedCallbackRegistered = true;

                    // Assigning default value e.g. null etc.
                    SetValue(defaultValue);
                    SetAndTest(eventsEnabled);

                    CheckNoChangeSet();

                    void SetValue(object newValue)
                    {
                        oldValue = value;
                        value    = newValue;
                    }

                    void SetAndTest(bool shouldInvokeEvents)
                    {
                        if (force)
                        {
                            w.ForceSetValue(value, propertyName);
                        }
                        else
                        {
                            w.SetValue(value, propertyName);
                        }

                        Assert.AreEqual(value, w.GetValue(propertyName));
                        CheckEventsInvoked(shouldInvokeEvents);
                    }

                    void CheckNoChangeSet()
                    {
                        if (force)
                        {
                            // Has to be set to the same
                            // When force == true, it will call callback
                            oldValue = value;
                        }

                        // No change in value - invoking events only when forced
                        SetAndTest(force && eventsEnabled);
                    }

                    void CheckEventsInvoked(bool shouldInvokeEvents)
                    {
                        if (shouldInvokeEvents)
                        {
                            Assert.AreEqual(1, propertyChangedEventInvokeCount);
                            propertyChangedEventInvokeCount = 0;

                            if (propertyChangedCallbackRegistered)
                            {
                                Assert.AreEqual(1, propertyChangedCallbackInvokeCount);
                                propertyChangedCallbackInvokeCount = 0;
                            }
                        }
                    }
                }
            }
        }
 /// <summary>
 /// Unregisters the <paramref name="propertyChangedCallback"/> so it will NOT be invoked when the property with the specified name changes.
 /// </summary>
 /// <param name="propertyName">Name of the property.</param>
 /// <param name="propertyChangedCallback"><see cref="PropertyChangedCallbackHandler"/> to be unregistered.</param>
 /// <exception cref="ArgumentNullException">
 ///     <para>
 ///         Parameter <paramref name="propertyName"/> is <c>null</c> or white space.
 ///     </para>
 ///     <para>
 ///         Actual instance does not contain registered property with the specified name.
 ///     </para>
 ///     <para>
 ///         Parameter <paramref name="propertyChangedCallback"/> is <c>null</c>.
 ///     </para>
 /// </exception>
 protected void UnregisterPropertyChangedCallback(string propertyName, PropertyChangedCallbackHandler propertyChangedCallback)
 {
     Helpers.ValidateObjectNotNull(propertyChangedCallback, nameof(propertyChangedCallback));
     GetPropertyData(propertyName, nameof(propertyName)).PropertyChangedCallback -= propertyChangedCallback;
 }
Exemple #5
0
 internal new void UnregisterPropertyChangedCallback(string propertyName, PropertyChangedCallbackHandler propertyChangedCallback)
 {
     base.UnregisterPropertyChangedCallback(propertyName, propertyChangedCallback);
 }
Exemple #6
0
 internal new void RegisterProperty(string name, Type type, object defaultValue, PropertyChangedCallbackHandler propertyChangedCallback)
 {
     base.RegisterProperty(name, type, defaultValue, propertyChangedCallback);
 }