/// <summary>
        /// Selects all valid block properties for duplication. If includeName == false, the name property
        /// will be excluded, where applicable.
        /// </summary>
        public int SelectAllProperties(bool includeName = true)
        {
            ClearSelection();
            int count = 0;

            for (int i = 0; i < dupeEntries.Count; i++)
            {
                BlockPropertyDupeEntry entry  = dupeEntries[i];
                IBlockMember           member = Block.BlockMembers[i];

                if (!includeName && i == 0 && (member.PropName == "Name" || member.PropName == "CustomName"))
                {
                    entry.isSelectedForDuplication = false;
                }
                else if (entry.canDuplicate && member.Enabled)
                {
                    entry.isSelectedForDuplication = true;
                    count++;
                }

                dupeEntries[i] = entry;
            }

            return(count);
        }
        /// <summary>
        /// Saves serialized copies of the properties currently selcted for duplication.
        /// </summary>
        public int CopySelectedProperties()
        {
            var propertyList = copiedProperties.propertyList;

            propertyList.Clear();

            copiedProperties.blockTypeID = Block.TypeID;

            for (int i = 0; i < dupeEntries.Count; i++)
            {
                BlockPropertyDupeEntry entry  = dupeEntries[i];
                IBlockMember           member = Block.BlockMembers[i];

                if (entry.isSelectedForDuplication && entry.canDuplicate && member.Enabled)
                {
                    var          property = member as IBlockProperty;
                    PropertyData?data     = property.GetPropertyData();

                    if (data != null)
                    {
                        propertyList.Add(data.Value);
                    }
                }
            }

            ClearSelection();

            return(propertyList.Count);
        }
        /// <summary>
        /// Sets the selection <see cref="BlockPropertyDupeEntry"/> at the corresponding index.
        /// Will not allow unsupported/disabled properties to be selected for duplication.
        /// </summary>
        public void SetMemberSelection(int index, bool isSelected)
        {
            BlockPropertyDupeEntry entry  = dupeEntries[index];
            IBlockMember           member = Block.BlockMembers[index];

            entry.isSelectedForDuplication = isSelected && entry.canDuplicate && member.Enabled;
            dupeEntries[index]             = entry;
        }
        /// <summary>
        /// Clears all property selections by setting isSelectedForDuplication to false.
        /// </summary>
        public void ClearSelection()
        {
            for (int i = 0; i < dupeEntries.Count; i++)
            {
                BlockPropertyDupeEntry entry = dupeEntries[i];
                entry.isSelectedForDuplication = false;

                dupeEntries[i] = entry;
            }
        }
        /// <summary>
        /// Assigns the given <see cref="PropertyBlock"/> as the current target and generates
        /// a parallel list of dupe entries correspondin to its block members.
        /// </summary>
        public void UpdateBlockMembers()
        {
            Reset();

            // Clear backup if target changes
            if (backup.Item1 != Block.TBlock)
            {
                backup.Item1             = null;
                backup.Item2.blockTypeID = null;
                backup.Item2.propertyList.Clear();
            }

            for (int i = 0; i < Block.BlockMembers.Count; i++)
            {
                IBlockMember member       = Block.BlockMembers[i];
                bool         canDuplicate = member is IBlockProperty;
                var          entry        = new BlockPropertyDupeEntry(canDuplicate);

                dupeEntries.Add(entry);
            }
        }