/// <summary>
        /// Adds new matches amongst all entries not included in the group.
        /// </summary>
        private void BttnCondApply_Click(object sender, RoutedEventArgs e)
        {
            uint numConditions = (uint)grouping.GetData("numConditions");
            bool wasEntryAdded = false;

            //Iterates through each entry that's not in the group.
            var entries = project.GetCollectionEntries(
                project.GetGroupingCollection(grouping))
                          .Except(project.GetGroupingEntries(grouping)).ToList();

            for (int i = 0; i < entries.Count; i++)
            {
                string name = ((string)entries[i].GetData("name")).ToLower();

                //Iterates through each condition.
                for (int j = 0; j < numConditions; j++)
                {
                    var condType = (GroupingCondType)
                                   grouping.GetData("conditionType" + j);

                    if (condType == GroupingCondType.ByLetter)
                    {
                        //Gets condition data.
                        var condFromLetter = ((string)
                                              grouping.GetData("condAddFromLetter" + j))
                                             .ToLower();
                        var condToLetter = ((string)
                                            grouping.GetData("condAddToLetter" + j))
                                           .ToLower();

                        //Skips invalid conditions.
                        if (condFromLetter?.Length == 0 ||
                            condToLetter?.Length == 0)
                        {
                            continue;
                        }

                        //Adds if the character range matches.
                        if (condFromLetter.CompareTo(name) <= 0 &&
                            condToLetter.CompareTo(name) >= 0)
                        {
                            wasEntryAdded = true;

                            project.AddGroupingEntryRef(
                                grouping.guid,
                                entries[i].guid);

                            //Removes the first match from the out group.
                            for (int k = 0; k < gui.LstbxOutGroup.Items.Count; k++)
                            {
                                if (((LstbxDataItem)gui.LstbxOutGroup.Items[k]).GetItem().guid ==
                                    entries[i].guid)
                                {
                                    gui.LstbxOutGroup.Items.Remove(entries[i]);
                                    break;
                                }
                            }

                            //Creates a new item for the entry.
                            var item = new LstbxDataItem(entries[i]);
                            item.Selected += new RoutedEventHandler((a, b) =>
                            {
                                ActiveEntry = item;

                                //Ensures only one item is selected at once.
                                if (gui.LstbxInGroup.Items.Contains(ActiveEntry))
                                {
                                    gui.LstbxOutGroup.SelectedItem = null;
                                }
                                else
                                {
                                    gui.LstbxInGroup.SelectedItem = null;
                                }
                            });

                            //Adds to the in group.
                            gui.LstbxInGroup.Items.Add(item);

                            break;
                        }
                    }
                }
            }

            //Grouping can only regain focus after adding entries if
            //any were actually added, so this ensures grouping has focus.
            if (wasEntryAdded)
            {
                EntryIncluded?.Invoke(this, null);
            }
        }
        /// <summary>
        /// Sets the page content based on existing material.
        /// </summary>
        public void ConstructPage()
        {
            gui = new PgGroupingGuiEdit();

            #region Grouping name
            //Sets the grouping name.
            if (string.IsNullOrWhiteSpace((string)grouping.GetData("name")))
            {
                gui.TxtblkGroupingName.Text = GlobalStrings.NameUntitled;
            }
            else
            {
                gui.TxtblkGroupingName.Text = (string)grouping.GetData("name");
            }

            //Handles changes to the grouping name.
            gui.TxtblkGroupingName.TextChanged += new TextChangedEventHandler((a, b) =>
            {
                if (!string.IsNullOrWhiteSpace(gui.TxtblkGroupingName.Text))
                {
                    grouping.SetData("name", gui.TxtblkGroupingName.Text);
                }

                //If the textbox is empty, it will keep the last character.
                gui.TxtblkGroupingName.Text = (string)grouping.GetData("name");

                DataNameChanged?.Invoke(this, null);
            });
            #endregion

            //All menu items are represented as entries for consistency.
            #region Menu Item Columns
            #region Menu item, move left/right
            var funcMenuItemMove = new Action(() =>
            {
                if (ActiveEntry == null)
                {
                    return;
                }

                //Moves the item in or out of the group (deletion/addition).
                if (gui.LstbxInGroup.Items.Contains(ActiveEntry))
                {
                    //Finds the entry reference for the current group that
                    //represents the entry, then removes the reference.
                    var refs = project.GetGroupingEntryRefs(grouping);
                    for (int i = 0; i < refs.Count; i++)
                    {
                        if ((ulong)refs[i].GetData("entryGuid") ==
                            ActiveEntry.GetItem().guid)
                        {
                            project.DeleteItemByGuid(refs[i].guid);
                        }
                    }

                    gui.LstbxInGroup.Items.Remove(ActiveEntry);
                    gui.LstbxOutGroup.Items.Add(ActiveEntry);
                }
                else
                {
                    project.AddGroupingEntryRef(
                        grouping.guid,
                        ActiveEntry.GetItem().guid);

                    gui.LstbxOutGroup.Items.Remove(ActiveEntry);
                    gui.LstbxInGroup.Items.Add(ActiveEntry);

                    EntryIncluded?.Invoke(this, null);
                }
            });
            #endregion

            #region Menuitem, selected
            var funcMenuItemSelected = new Action <LstbxDataItem>((newItem) =>
            {
                ActiveEntry = newItem;

                //Ensures only one item is selected at once.
                if (gui.LstbxInGroup.Items.Contains(ActiveEntry))
                {
                    gui.LstbxOutGroup.SelectedItem = null;
                }
                else
                {
                    gui.LstbxInGroup.SelectedItem = null;
                }
            });
            #endregion

            #region Populate menu items
            //Adds every menu item in its original order.
            var col        = project.GetGroupingCollection(grouping);
            var entries    = project.GetGroupingEntries(grouping);
            var colEntries = project.GetCollectionEntries(col);

            //Adds entries to their respective lists via group inclusiveness.
            for (int i = 0; i < colEntries.Count; i++)
            {
                var item = new LstbxDataItem(colEntries[i]);

                //Looks to see if this entry is in the group.
                var result = entries.Find(new Predicate <DataItem>((a) =>
                {
                    return(a.guid.Equals(colEntries[i].guid));
                }));

                //Adds the entry based on whether it's in the group.
                if (result != null)
                {
                    gui.LstbxInGroup.Items.Add(item);
                }
                else
                {
                    gui.LstbxOutGroup.Items.Add(item);
                }

                //Handles item selection.
                item.Selected += new RoutedEventHandler((a, b) =>
                {
                    funcMenuItemSelected(item);
                });
            }
            #endregion

            #region Keyboard event handling
            gui.LstbxInGroup.KeyDown += new KeyEventHandler((a, b) =>
            {
                //Right key pressed: Move to 2nd column
                if (b.Key == Key.Right && b.IsDown && ActiveEntry != null)
                {
                    funcMenuItemMove();
                }
            });

            gui.LstbxOutGroup.KeyDown += new KeyEventHandler((a, b) =>
            {
                //Left key pressed: Move to 1st column
                if (b.Key == Key.Left && b.IsDown &&
                    gui.LstbxOutGroup.SelectedItem != null)
                {
                    funcMenuItemMove();
                }
                #endregion
            });

            #endregion

            #region Left arrow key pressed
            gui.BttnMoveLeft.MouseDown += new MouseButtonEventHandler((a, b) =>
            {
                if (gui.LstbxOutGroup.SelectedItem != null)
                {
                    funcMenuItemMove();
                }
            });
            #endregion

            #region Right arrow key pressed
            gui.BttnMoveRight.MouseDown += new MouseButtonEventHandler((a, b) =>
            {
                if (gui.LstbxInGroup.SelectedItem != null)
                {
                    funcMenuItemMove();
                }
            });
            #endregion

            #region Grouping conditions
            gui.BttnCondAdd.Click   += BttnCondAdd_Click;
            gui.BttnCondApply.Click += BttnCondApply_Click;

            //Populates all grouping conditions.
            uint numConditions = (uint)grouping.GetData("numConditions");
            for (int i = 0; i < numConditions; i++)
            {
                var condType = (GroupingCondType)
                               grouping.GetData("conditionType" + i);

                switch (condType)
                {
                case (GroupingCondType.ByLetter):
                    string condFromLetter = (string)
                                            grouping.GetData("condAddFromLetter" + i);
                    string condToLetter = (string)
                                          grouping.GetData("condAddToLetter" + i);

                    gui.GroupConditions.Children.Add(
                        AddConditionByRange(condFromLetter, condToLetter, (uint)i));
                    break;
                }
            }
            #endregion
        }