void RelationModeChangeIgnore(IgnoredMode mode)
        {
            if (selectedRalationModeRowIndex == -1)
            {
                return;
            }
            int lastSelected = selectedRalationModeRowIndex;

            foreach (DataGridViewRow row in dataGridView1.Rows)
            {
                if (row.Selected)
                {
                    var record = allRecords[(Guid)row.Tag];
                    var result = markIgnoreCallback(record.Id, mode);
                    if (result)
                    {
                        record.IgnoredMode = mode;
                        row.Cells[5].Value = SimilarFileHelper.IgnoredModeToString(mode);
                    }
                    lastSelected = row.Index;
                }
            }

            RelationModeMoveNext(lastSelected);
        }
        void FileModeChangeIgnore(IgnoredMode mode)
        {
            if (selectedFileModeFile2RowIndex == -1)
            {
                return;
            }
            int lastSelected = selectedFileModeFile2RowIndex;

            listView3.BeginUpdate();
            foreach (ListViewItem listViewItem in listView3.Items)
            {
                if (listViewItem.Selected)
                {
                    //Tuple<Guid, Guid, bool>(similarFileRecordId, fileId, isFile1InMain)
                    Tuple <Guid, Guid, bool> tag = (Tuple <Guid, Guid, bool>)listViewItem.Tag;
                    var record = allRecords[tag.Item1];
                    var result = markIgnoreCallback(tag.Item1, mode);
                    if (result)
                    {
                        record.IgnoredMode            = mode;
                        listViewItem.SubItems[4].Text = SimilarFileHelper.IgnoredModeToString(mode);
                    }
                    lastSelected = listViewItem.Index;
                }
            }
            listView3.EndUpdate();
            FileModeMoveNext(lastSelected);
        }
        void FileModeLoadSimilarRecords()
        {
            var showHiddenRecord = checkBox1.Checked;

            fileModeFile2Changing = true;
            listView3.Items.Clear();
            var relatedRecords = groupedFiles[selectedGroupId][fileModeFile1SelectedFileId];

            ImageStoreSimilarFile[] grouped;
            if (showHiddenRecord)
            {
                grouped = relatedRecords.ConvertAll(i => allRecords[i]).OrderBy(i => i.DifferenceDegree).ToArray();
            }
            else
            {
                grouped = relatedRecords.ConvertAll(i => allRecords[i]).Where(i => i.IgnoredMode == IgnoredMode.Effective).OrderBy(i => i.IgnoredModeCode).ThenBy(i => i.DifferenceDegree).ToArray();
            }

            if (grouped.Length > 0)
            {
                List <ListViewItem> items = new List <ListViewItem>();
                foreach (var similarFileRecord in grouped)
                {
                    var      isFile1InMain = similarFileRecord.File1Id == fileModeFile1SelectedFileId;
                    FileInfo file;
                    if (isFile1InMain)
                    {
                        file = allFileInfo[similarFileRecord.File2Id];
                    }
                    else
                    {
                        file = allFileInfo[similarFileRecord.File1Id];
                    }
                    var selected = selectedFiles.Contains(file.FileId);
                    items.Add(new ListViewItem(new string[] {
                        similarFileRecord.DifferenceDegree.ToString("0.0000"),
                        file.FileNameWithExtension, file.PathToDirectory, file.FileSize.ToString(),
                        SimilarFileHelper.IgnoredModeToString(similarFileRecord.IgnoredMode)
                    })
                    {
                        Checked = selected,
                        Tag     = new Tuple <Guid, Guid, bool>(similarFileRecord.Id, file.FileId, isFile1InMain)
                    });
                }

                listView3.Items.AddRange(items.OrderBy(i => i.SubItems[2].Text).ThenBy(i => i.SubItems[0].Text).ThenBy(i => i.SubItems[1].Text).ToArray());
                listView3.Items[0].Selected = true;
            }
            fileModeFile2Changing = false;
        }
        void LoadToRelationTab()
        {
            dataGridView1.Rows.Clear();
            var showHiddenRecord = checkBox1.Checked;

            //Dictionary<Guid, List<ImageStoreSimilarFile>> grouped;
            //Dictionary<Guid, List<Guid>> grouped;

            List <ImageStoreSimilarFile> grouped;

            if (selectedGroupId != -2)
            {
                if (showHiddenRecord)
                {
                    grouped = groupedFiles[selectedGroupId].Values.SelectMany(i => i.Select(j => allRecords[j])).Distinct().OrderBy(i => i.IgnoredModeCode).ThenBy(i => i.DifferenceDegree).ToList();
                }
                else
                {
                    grouped = groupedFiles[selectedGroupId].Values.SelectMany(i => i.Select(j => allRecords[j])).Where(i => i.IgnoredMode == IgnoredMode.Effective).Distinct().OrderBy(i => i.DifferenceDegree).ToList();
                }
            }
            else
            {
                grouped = null;
            }

            if (grouped?.Count > 0)
            {
                DataGridViewRow[] rows = new DataGridViewRow[grouped.Count];
                Parallel.For(0, grouped.Count, rowIndex =>
                {
                    var similarFileRecord = grouped[rowIndex];
                    var selected1         = selectedFiles.Contains(similarFileRecord.File1Id);
                    var selected2         = selectedFiles.Contains(similarFileRecord.File2Id);
                    string selectedText;
                    if (selected1)
                    {
                        if (selected2)
                        {
                            selectedText = "✓ 1:\n✓ 2:";
                        }
                        else
                        {
                            selectedText = "✓ 1:\n2:";
                        }
                    }
                    else
                    {
                        if (selected2)
                        {
                            selectedText = "1:\n✓ 2:";
                        }
                        else
                        {
                            selectedText = "1:\n2:";
                        }
                    }
                    var file1 = allFileInfo[similarFileRecord.File1Id];
                    var file2 = allFileInfo[similarFileRecord.File2Id];

                    DataGridViewRow row = new DataGridViewRow();
                    row.Height          = (int)(row.Height * 1.5);
                    row.Cells.Add(new DataGridViewTextBoxCell()
                    {
                        Value = similarFileRecord.DifferenceDegree.ToString("0.0000")
                    });
                    row.Cells.Add(new DataGridViewTextBoxCell()
                    {
                        Value = selectedText
                    });
                    row.Cells.Add(new DataGridViewTextBoxCell()
                    {
                        Value = file1.FileNameWithExtension + "\n" + file2.FileNameWithExtension
                    });
                    row.Cells.Add(new DataGridViewTextBoxCell()
                    {
                        Value = file1.PathToDirectory + "\n" + file2.PathToDirectory
                    });
                    row.Cells.Add(new DataGridViewTextBoxCell()
                    {
                        Value = file1.FileSize.ToString() + "\n" + file2.FileSize.ToString()
                    });
                    row.Cells.Add(new DataGridViewTextBoxCell()
                    {
                        Value = SimilarFileHelper.IgnoredModeToString(similarFileRecord.IgnoredMode)
                    });
                    row.Tag        = similarFileRecord.Id;
                    rows[rowIndex] = row;
                });
                dataGridView1.Rows.AddRange(rows);
                dataGridView1.Rows[0].Selected = true;
            }
            else
            {
                doublePictureBox1.ClearPictures();
            }
        }