GetHashCode override not working

Mar 18, 2015 at 3:20 PM
Edited Mar 18, 2015 at 3:28 PM
I have a class that contains an ObservableCollection<String>. I do not want to include it in the IsDirty check so I added the override GetHashCode() method but this override is not being used.


As soon as this program starts the Model is marked dirty. Is there a reason the override of GetHashCode is not being called (I put a break point 'return GetHashCode(this, "DatabaseList");' it and it never breaks on this point)? Have I set this up incorrectly?

I have added a test project for this to GitHub (https://github.com/brianke/AbstractIsDirtyTest.git) and learned how to add ignore file ! :)



Here are the Model and ViewModel:
    public class ConfigModel : ModelBase<ConfigModel>
    {
        #region Initialization & Cleanup

        // Overriding the GetHashCode prevents the Clone operation from marking an 
        // object Dirty when it is first cloned
        public override int GetHashCode()
        {
            return GetHashCode(this, "DatabaseList");
        }
        private int GetHashCode(object item, params string[] excludeProps)
        {
            int hashCode = 0;
            foreach (var prop in item.GetType().GetProperties())
            {
                if (!excludeProps.Contains(prop.Name))
                {
                    object propVal = prop.GetValue(item, null);
                    if (propVal != null)
                    {
                        hashCode = hashCode ^ propVal.GetHashCode();
                    }
                }
            }
            return hashCode;
        }

        // Default ctor
        public ConfigModel()  {  }

        #endregion Initialization & Cleanup


        #region Properties

        /// <summary>
        /// DatabaseList 
        /// </summary>
        public ObservableCollection<String> DatabaseList
        {
            get { return _DatabaseList; }
            set
            {
                if (_DatabaseList != value)
                {
                    _DatabaseList = value;
                    NotifyPropertyChanged(m => m.DatabaseList);
                }
            }

        }
        private ObservableCollection<String> _DatabaseList = new ObservableCollection<String>();
        
        #endregion Properties
    }
and this associated view model:
    public class ConfigViewModelDetail : ViewModelDetailBase<ConfigViewModelDetail, ConfigModel>
    {
        // Default ctor
        public ConfigViewModelDetail() 
        {
            base.Model = ConfigModel;
            BeginEdit();        
        }

        public ConfigModel ConfigModel
        {
            get
            {
                return _ConfigModel;
            }
            set
            {
                _ConfigModel = value;
                NotifyPropertyChanged(m => m.ConfigModel);
            }
        }
        private ConfigModel _ConfigModel = new ConfigModel();

    }
Mar 19, 2015 at 4:07 PM
Thought I should mention that when I use Snoops to view the data context and drill down to the label containing the IsDirty binding, the override GetHashCode() in ConfigViewModelDetail is used.

Any idea why the override would be used in this case but not on BeginEdit()?
Coordinator
Mar 19, 2015 at 8:01 PM
Thanks for your patience. I will take a lol at this
Coordinator
Mar 20, 2015 at 7:51 AM
I submitted a pull request in which I added the Common project from source, so that you can step into the IsDirty property to see exactly where GetHashCode is being called. Relying on the principle of "teaching a man to fish," I though it would be good to set things up for you to debug the problem. :) When you step into the code, you should set a breakpoint on the AreSame method in ModelExtensions.cs. When you step into GetObjectHashCode, you'll see that GetHashCode is being called on each property of the model (ConfigModel), not on the model itself.

If you wish to exclude the DatabaseList property on the model, then create a custom class that extends ObservableCollection<string> and override GetHashCode there to return 0.

Cheers,
Tony