for Push.

This commit is contained in:
nobobo
2026-06-01 13:23:34 +09:00
parent 9e093ea99f
commit a6550e9928
93 changed files with 10393 additions and 0 deletions
+726
View File
@@ -0,0 +1,726 @@
using KssSmaPlaLib.Commons;
using KssSmaPlaLib.Forms.ContextMenuFunction;
using KssSmaPlaLib.Ini;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace KssSmaPlaLib.Forms
{
public class DgvHelper
{
/// <summary>
/// 汎用的な初期化
/// </summary>
/// <param name="dgv"></param>
public static void Initialize(DataGridView dgv)
{
// 行選択
dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
// 行ヘッダ消去
dgv.RowHeadersVisible = false;
// 編集不可
dgv.ReadOnly = true;
// ユーザ操作制限
dgv.AllowUserToAddRows = false;
dgv.AllowUserToDeleteRows = false;
dgv.AllowUserToOrderColumns = false;
dgv.AllowUserToResizeColumns = true;
dgv.AllowUserToResizeRows = false;
// 列ヘッダはセンタリング
dgv.ColumnHeadersDefaultCellStyle.Alignment=DataGridViewContentAlignment.MiddleCenter;
//// ソート用余白を消す
//dgv.ColumnHeadersDefaultCellStyle.Padding = new Padding(0);
// セル内余白(上下左右)をゼロに
dgv.DefaultCellStyle.Padding = new Padding(0);
// 行高さの自動調整
dgv.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;
// ダブルバッファ(プロパティが隠れている)
var type = typeof(DataGridView);
var prop = type.GetProperty("DoubleBuffered",
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
prop.SetValue(dgv, true, null);
}
/// <summary>
/// 列ヘッダのソート用余白を消す
/// ※列が確定してからCallすること
/// </summary>
/// <param name="dgv"></param>
//public static void ClearColumnHeaderSortYohaku(DataGridView dgv)
//{
// // 列ヘッダの幅にソート用の幅は不要
// //foreach (DataGridViewColumn col in dgv.Columns) col.SortMode = DataGridViewColumnSortMode.NotSortable;
// // 何をやってもダメなので、テキストの先頭に余白入れます!👉ダメ!orz
// //const string YOHAKU = "       ";
// //foreach (DataGridViewColumn col in dgv.Columns) col.HeaderText = YOHAKU + col.HeaderText;
//}
// どちらのDTOでも使える共通バインド関数
public static void BindListWithAttributeHeaders<T>(
DataGridView grid,
IList<T> source,
bool isForce = false)
{
// 強制でないとき、データソースありなら何もしない
if (!(grid.DataSource is null) && !isForce) return;
// データバインド完了後にヘッダー等を属性で上書き
grid.DataBindingComplete += (_, __) => ApplyAttributeHeaders<T>(grid);
// 「とりあえず ToString() で文字列表示」したい場合の統一フォーマット
grid.CellFormatting += (_, e) =>
{
try
{
// AutoGenerateColumnsだと各セルの Value はプロパティ値になります
// ここで ToString() 統一(nullは空文字に)
if (e.Value == null) { e.Value = string.Empty; e.FormattingApplied = true; return; }
// 文化依存や日付/数値の既定書式を崩したくなければコメントアウト推奨
if (!(e.Value is bool) &&
string.IsNullOrEmpty(grid.Columns[e.ColumnIndex].DefaultCellStyle.Format))
{
e.Value = e.Value.ToString();
e.FormattingApplied = true;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
};
grid.AutoGenerateColumns = true;
// 変更通知を効かせたい場合は BindingList に包む
var bindingList = source is BindingList<T> bl ? bl : new BindingList<T>(source);
// BindingSource 経由が安定
var bs = new BindingSource { DataSource = bindingList };
grid.DataSource = bs;
}
private const string KEY_NAME_DISPLAY_NAME_CSV = "DisplayNameCsv";
/// <summary>
/// プライベートな子関数
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="grid"></param>
public static void ApplyAttributeHeaders<T>(DataGridView grid)
{
// 編集した表示名
var csv = IniHelper.ReadValue(null, grid.Parent.Name + "." + grid.Name, KEY_NAME_DISPLAY_NAME_CSV);
var props = TypeDescriptor.GetProperties(typeof(T))
.Cast<PropertyDescriptor>()
.ToDictionary(p => p.Name);
foreach (DataGridViewColumn col in grid.Columns)
{
var key = col.DataPropertyName ?? col.Name;
if (key is null) continue;
if (props.TryGetValue(key, out var pd))
{
// タグに入れておく(PropertyDescriptor型)
col.Tag = pd;
// 列ヘッダーを [DisplayName] に
col.HeaderText = pd.DisplayName;
// 表示名を登録されてたら、置き換える
var editName = StringUxer.GetStringByIndexFormCsv(csv,col.Index,string.Empty);
if (!string.IsNullOrEmpty(editName)) col.HeaderText = editName;
// 文字寄せ
var alignment =
(col.HeaderText.IndexOf("[R]") >= 0 ? DataGridViewContentAlignment.MiddleRight :
(col.HeaderText.IndexOf("[C]") >= 0 ? DataGridViewContentAlignment.MiddleCenter :
DataGridViewContentAlignment.MiddleLeft));
col.DefaultCellStyle.Alignment = alignment;
col.HeaderText = col.HeaderText.Replace("[L]", "").Replace("[C]", "").Replace("[R]", "");
// [Browsable(false)] の列は非表示(AutoGenerateでも列が立つ場合の保険)
var browsableAttr = pd.Attributes.OfType<BrowsableAttribute>().FirstOrDefault();
if (browsableAttr != null && !browsableAttr.Browsable)
{
col.Visible = false;
continue;
}
// 読み取り専用属性の尊重
col.ReadOnly = pd.IsReadOnly;
// 便利系:ソートを自動に
// col.SortMode = DataGridViewColumnSortMode.Automatic;
// 必要なら列幅の初期値
// col.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
}
}
}
private const string INI_KEY_COL_WIDTH_CSV = "ColWidthCsv";
/// <summary>
/// 列幅保存(FormのFormClosingにてCall
/// </summary>
/// <param name="dgv"></param>
public static void DgvSaveColWidth(DataGridView dgv)
{
var section = dgv.Parent.Name + "." + dgv.Name;
var list = new List<int>();
foreach(DataGridViewColumn col in dgv.Columns) list.Add(col.Width);
IniHelper.WriteValue(null, section, INI_KEY_COL_WIDTH_CSV, string.Join(",", list));
}
/// <summary>
/// 列幅復元(FormのコンストラクタにてCall)
/// </summary>
/// <param name="dgv"></param>
public static void DgvLoadColWidth(DataGridView dgv)
{
var section = dgv.Parent.Name + "." + dgv.Name;
var list = IniHelper.ReadValue(null, section,INI_KEY_COL_WIDTH_CSV).Split(',').ToList();
foreach (DataGridViewColumn col in dgv.Columns)
{
if (list.Count - 1 < col.Index) break;
if (!int.TryParse(list[col.Index], out int val)) break;
col.Width = val;
}
}
private const string INI_KEY_FONT_CSV = "Font";
public static void DgvSelectFont(Form form, DataGridView dgv)
{
if (!FontUxer.SelectFont(form, form.Name, dgv.Name + ".Font", dgv.DefaultCellStyle.Font, out var font)) return;
DgvSetFontFromFont(dgv, font);
DgvSaveFontToIni(dgv);
}
public static void DgvSetFontFromFont(DataGridView dgv, Font font)
{
var font2 = new Font(font.Name, font.Size, font.Bold ? FontStyle.Bold : FontStyle.Regular);
dgv.DefaultCellStyle.Font = font2;
dgv.ColumnHeadersDefaultCellStyle.Font = font2;
dgv.AutoResizeRows();
}
public static void DgvSaveFontToIni(DataGridView dgv)
{
var fontCsv =
dgv.ColumnHeadersDefaultCellStyle.Font.Name + "," +
dgv.ColumnHeadersDefaultCellStyle.Font.Size.ToString() + "," +
dgv.ColumnHeadersDefaultCellStyle.Font.Bold.ToString();
IniHelper.WriteValue(null, dgv.Parent.Name + "." + dgv.Name, INI_KEY_FONT_CSV, fontCsv);
}
public static void DgvLoadFontFromIni(DataGridView dgv)
{
var defaultFontCsv =
dgv.ColumnHeadersDefaultCellStyle.Font.Name + "," +
dgv.ColumnHeadersDefaultCellStyle.Font.Size.ToString() + "," +
dgv.ColumnHeadersDefaultCellStyle.Font.Bold.ToString();
var iniFontCsv = IniHelper.ReadValue(null, dgv.Parent.Name + "." + dgv.Name, INI_KEY_FONT_CSV, defaultFontCsv);
var fontItems = iniFontCsv.Split(',');
if (fontItems.Length != 3) fontItems = defaultFontCsv.Split(',');
if (float.TryParse(fontItems[1], out var size) == false) size = dgv.ColumnHeadersDefaultCellStyle.Font.Size;
if (bool.TryParse(fontItems[2], out var bold) == false) bold = dgv.ColumnHeadersDefaultCellStyle.Font.Bold;
var font = new Font(fontItems[0], size, bold ? FontStyle.Bold : FontStyle.Regular);
dgv.DefaultCellStyle.Font = font;
dgv.ColumnHeadersDefaultCellStyle.Font = font;
dgv.AutoResizeRows();
}
private const string KEY_NAME_DISPLAY_INDEX_CSV = "DisplayIndexCsv";
private const string KEY_NAME_COLUMN_VISIBLE_CSV = "ColumnVisibleCsv";
/// <summary>
/// INIの列表示順をDGVに反映
/// </summary>
/// <param name="dgv"></param>
public static void SetColumnDisplayIndexFromIni(DataGridView dgv)
{
// 表示順(DisplayIndex)の設定
var csv = IniHelper.ReadValue(null, dgv.Parent.Name + "." + dgv.Name, KEY_NAME_DISPLAY_INDEX_CSV);
if (string.IsNullOrEmpty(csv)) return;
var items = csv.Split(',');
if (items.Length != dgv.Columns.Count) return;
List<int> displayIndexList = new List<int>();
foreach ( var item in items) displayIndexList.Add(int.Parse(item));
for (var cnt = 0; cnt < dgv.Columns.Count; cnt++)
{
var index = displayIndexList.IndexOf(cnt);
dgv.Columns[index].DisplayIndex = cnt;
}
// 列の表示/非表示の設定
csv = IniHelper.ReadValue(null, dgv.Parent.Name + "." + dgv.Name, KEY_NAME_COLUMN_VISIBLE_CSV);
if (string.IsNullOrEmpty(csv)) return;
items = csv.Split(',');
if (items.Length != dgv.Columns.Count) return;
List<bool> visibleList = new List<bool>();
foreach (var item in items) visibleList.Add(bool.TryParse(item, out var boolValue) ? boolValue : true);
for (var cnt = 0; cnt < dgv.Columns.Count; cnt++)
{
dgv.Columns[cnt].Visible = visibleList[cnt];
}
}
public static void MoveRow(DataGridView dgv, int rowIndex, bool moveUp)
{
// 移動先のインデックスを計算
int targetIndex = moveUp ? rowIndex - 1 : rowIndex + 1;
// 範囲チェック(一番上より上、または一番下より下には行かない)
if (targetIndex < 0 || targetIndex >= dgv.Rows.Count - (dgv.AllowUserToAddRows ? 1 : 0))
{
return;
}
// 選択状態などを保持したい場合の準備
DataGridViewRow row = dgv.Rows[rowIndex];
// 一旦削除して挿入し直す
dgv.Rows.RemoveAt(rowIndex);
dgv.Rows.Insert(targetIndex, row);
// 移動後の行を選択状態にする(ユーザー体験向上)
dgv.ClearSelection();
dgv.Rows[targetIndex].Selected = true;
dgv.CurrentCell = dgv.Rows[targetIndex].Cells[0];
}
private const string INI_KEY_DGV_ROW_HEADER_HEIGHT = "DgvRowHeaderHeight";
/// <summary>
/// ヘッダ行の高さ保存
/// </summary>
/// <param name="dgv"></param>
public static void DgvSaveHeaderHeight(DataGridView dgv)
{
var section = dgv.Parent.Name + "." + dgv.Name;
IniHelper.WriteValue(null, section, INI_KEY_DGV_ROW_HEADER_HEIGHT, dgv.ColumnHeadersHeight.ToString());
}
/// <summary>
/// ヘッダ行の高さロード
/// </summary>
/// <param name="dgv"></param>
public static void DgvLoadHeaderHeight(DataGridView dgv)
{
var section = dgv.Parent.Name + "." + dgv.Name;
var str = IniHelper.ReadValue(null, section, INI_KEY_DGV_ROW_HEADER_HEIGHT, dgv.ColumnHeadersHeight.ToString());
dgv.ColumnHeadersHeight = int.TryParse(str, out var intValue) ? intValue : dgv.ColumnHeadersHeight;
}
/// <summary>
/// 非表示列の再表示
/// </summary>
/// <param name="dgv"></param>
public static void DgvRedispAllColumn(DataGridView dgv)
{
foreach (DataGridViewColumn col in dgv.Columns) col.Visible = true;
}
private const string INI_KEY_COL_VISIBLE_CSV = "ColVisibleCsv";
/// <summary>
/// 列の表示非表示を保存
/// </summary>
/// <param name="dgv"></param>
public static void DgvSaveColVisible(DataGridView dgv)
{
var section = dgv.Parent.Name + "." + dgv.Name;
var list = new List<bool>();
foreach (DataGridViewColumn col in dgv.Columns) list.Add(col.Visible);
IniHelper.WriteValue(null, section, INI_KEY_COL_VISIBLE_CSV, string.Join(",", list));
}
/// <summary>
/// 列の表示非表示をロード
/// </summary>
/// <param name="dgv"></param>
public static void DgvLoadColVisible(DataGridView dgv)
{
var section = dgv.Parent.Name + "." + dgv.Name;
var list = IniHelper.ReadValue(null, section, INI_KEY_COL_VISIBLE_CSV).Split(',').ToList();
foreach (DataGridViewColumn col in dgv.Columns)
{
if (list.Count - 1 < col.Index) break;
if (!bool.TryParse(list[col.Index], out bool val)) break;
col.Visible = val;
}
}
private const string INI_KEY_COL_DISPLAY_INDEX_CSV = "ColDisplayIndexCsv";
/// <summary>
/// 列の表示順インデックスを保存
/// </summary>
/// <param name="dgv"></param>
public static void DgvSaveColDisplayIndex(DataGridView dgv)
{
var section = dgv.Parent.Name + "." + dgv.Name;
var list = new List<string>();
foreach (DataGridViewColumn col in dgv.Columns) list.Add($"{col.Name}={col.DisplayIndex}");
IniHelper.WriteValue(null, section, INI_KEY_COL_DISPLAY_INDEX_CSV, string.Join(",", list));
}
/// <summary>
/// 列の表示順インデックスをロード
/// </summary>
/// <param name="dgv"></param>
public static void DgvLoadColDisplayIndex(DataGridView dgv)
{
var section = dgv.Parent.Name + "." + dgv.Name;
var list = IniHelper.ReadValue(null, section, INI_KEY_COL_DISPLAY_INDEX_CSV).Split(',').ToList();
if (list.Count == 1 && string.IsNullOrEmpty(list[0])) return;
Dictionary<int,string> dic = new Dictionary<int,string>();
foreach (var str in list)
{
dic.Add(int.Parse(str.Split('=')[1]), str.Split('=')[0]);
}
// DisplayIndexは小さい方から設定しないと崩れる
foreach (var di in dic.Keys.OrderBy(m => m))
{
dgv.Columns[dic[di]].DisplayIndex = di;
}
}
/// <summary>
/// 列幅の自動調整
/// </summary>
/// <param name="dgv"></param>
public static void DgvColumnWidthAutoAdjust(DataGridView dgv)
{
dgv.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);
}
/// <summary>
/// 行高さの自動調整
/// </summary>
/// <param name="dgv"></param>
public static void DgvRowHeightAutoAdjust(DataGridView dgv)
{
dgv.AutoResizeRows(DataGridViewAutoSizeRowsMode.AllCells);
}
/// <summary>
/// 列固定
/// </summary>
/// <param name="dgv"></param>
public static void DgvColumnFix(DataGridView dgv)
{
if (dgv.CurrentCell == null) return;
// 1. 今クリックした列の「見た目の位置」を取得
int targetDisplayIndex = dgv.CurrentCell.OwningColumn.DisplayIndex;
// 2. いったん全列の固定を解除(これをしないとエラーになる場合がある)
DgvColumnFixKaijo(dgv);
// 3. 見た目の位置(DisplayIndex)が、ターゲット以下の列をすべて固定!
// ※DisplayIndexの小さい順(左側から順)にFrozenをかけていくのがコツ
var targetColumns = dgv.Columns.Cast<DataGridViewColumn>()
.OrderBy(c => c.DisplayIndex);
foreach (var col in targetColumns)
{
if (col.DisplayIndex <= targetDisplayIndex)
{
col.Frozen = true;
}
}
}
/// <summary>
/// 列固定解除
/// </summary>
/// <param name="dgv"></param>
public static void DgvColumnFixKaijo(DataGridView dgv)
{
// 2. いったん全列の固定を解除(これをしないとエラーになる場合がある)
foreach (DataGridViewColumn col in dgv.Columns)
{
col.Frozen = false;
}
}
private const string INI_KEY_COL_FROZEN_CSV = "ColFrozenCsv";
/// <summary>
/// 列の固定を保存
/// </summary>
/// <param name="dgv"></param>
public static void DgvSaveColFrozen(DataGridView dgv)
{
var section = dgv.Parent.Name + "." + dgv.Name;
var list = new List<bool>();
foreach (DataGridViewColumn col in dgv.Columns) list.Add(col.Frozen);
IniHelper.WriteValue(null, section, INI_KEY_COL_FROZEN_CSV, string.Join(",", list));
}
/// <summary>
/// 列の固定をロード
/// </summary>
/// <param name="dgv"></param>
public static void DgvLoadColFrozen(DataGridView dgv)
{
var section = dgv.Parent.Name + "." + dgv.Name;
var list = IniHelper.ReadValue(null, section, INI_KEY_COL_FROZEN_CSV).Split(',').ToList();
foreach (DataGridViewColumn col in dgv.Columns)
{
if (list.Count - 1 < col.Index) break;
if (!bool.TryParse(list[col.Index], out bool val)) break;
col.Frozen = val;
}
}
private const string INI_KEY_DGV_HEADER_BACK_COLOR = "DgvHeaderBackColor";
/// <summary>
/// ヘッダ背景色選択
/// </summary>
/// <param name="form"></param>
/// <param name="dgv"></param>
public static void DgvSelectHeaderBackColor(Form form, DataGridView dgv)
{
using (ColorDialog cd = new ColorDialog())
{
// 今の色を初期選択にしておく
cd.Color = dgv.ColumnHeadersDefaultCellStyle.BackColor;
if (cd.ShowDialog() == DialogResult.OK)
{
// 1. フォームの背景色を即時変更
dgv.ColumnHeadersDefaultCellStyle.BackColor = cd.Color;
// 文字色を計算して算出し設定
dgv.ColumnHeadersDefaultCellStyle.ForeColor = ColorHelper.GetContrastColor(dgv.ColumnHeadersDefaultCellStyle.BackColor);
// 2. 🔥 Colorを16進数(#RRGGBB)に変換してINIに書き込み
string colorHex = ColorTranslator.ToHtml(cd.Color);
IniHelper.WriteValue(null, form.Name, INI_KEY_DGV_HEADER_BACK_COLOR, colorHex);
}
}
}
/// <summary>
/// ヘッダ背景色(名前でマッチした列のみ)選択
/// </summary>
/// <param name="form"></param>
/// <param name="dgv"></param>
/// <param name="colNamePattern"></param>
/// <param name="iniKey"></param>
public static void DgvSelectHeaderBackColorWithNameMatch(Form form, DataGridView dgv, string colNamePattern, string iniKey)
{
// マッチする列を探し、現在の色を採取
Color? color = null;
foreach (DataGridViewColumn col in dgv.Columns)
{
if (StringUxer.WildcardMatch(col.Name, colNamePattern))
{
color = col.HeaderCell.Style.BackColor;
}
}
if (color == null)
{
MessageBox.Show(form, $"パターンにマッチする列なし[パターン:{colNamePattern}]");
return;
}
using (ColorDialog cd = new ColorDialog())
{
// 今の色を初期選択にしておく
cd.Color = (Color)color;
if (cd.ShowDialog() == DialogResult.OK)
{
var backColor = cd.Color;
// 文字色を計算して算出し設定
var foreColor = ColorHelper.GetContrastColor(backColor);
// DGVに反映
foreach (DataGridViewColumn col in dgv.Columns)
{
if (StringUxer.WildcardMatch(col.Name, colNamePattern))
{
col.HeaderCell.Style.BackColor = backColor;
col.HeaderCell.Style.ForeColor = foreColor;
}
}
// 2. 🔥 Colorを16進数(#RRGGBB)に変換してINIに書き込み
string colorHex = ColorTranslator.ToHtml(cd.Color);
IniHelper.WriteValue(null, form.Name, iniKey, colorHex);
}
}
}
/// <summary>
/// ヘッダ背景色をINIから取得して設定
/// </summary>
/// <param name="form"></param>
public static void DgvSetHeaderBackColorFromIni(Form form, DataGridView dgv)
{
var colorHex = IniHelper.ReadValue(null, form.Name, INI_KEY_DGV_HEADER_BACK_COLOR, ColorTranslator.ToHtml(dgv.ColumnHeadersDefaultCellStyle.BackColor));
dgv.ColumnHeadersDefaultCellStyle.BackColor = ColorTranslator.FromHtml(colorHex);
// 文字色を計算して算出し設定
dgv.ColumnHeadersDefaultCellStyle.ForeColor = ColorHelper.GetContrastColor(dgv.ColumnHeadersDefaultCellStyle.BackColor);
}
/// <summary>
/// ヘッダ背景色をINIから取得して設定(名前マッチング)
/// </summary>
/// <param name="form"></param>
/// <param name="dgv"></param>
/// <param name="colNamePattern"></param>
/// <param name="iniKey"></param>
public static void DgvSetHeaderBackColorFromIniWithNameMatch(Form form, DataGridView dgv, string colNamePattern, string iniKey)
{
// マッチする列を探し、現在の色を採取
Color? color = null;
foreach (DataGridViewColumn col in dgv.Columns)
{
if (StringUxer.WildcardMatch(col.Name, colNamePattern))
{
color = col.HeaderCell.Style.BackColor;
}
}
if (color == null)
{
MessageBox.Show(form, $"パターンにマッチする列なし[パターン:{colNamePattern}]");
return;
}
// INIから取得
var colorHex = IniHelper.ReadValue(null, form.Name, iniKey, ColorTranslator.ToHtml((Color)color));
var backColor = ColorTranslator.FromHtml(colorHex);
var foreColor = ColorHelper.GetContrastColor(backColor);
// マッチする列に設定
foreach (DataGridViewColumn col in dgv.Columns)
{
if (StringUxer.WildcardMatch(col.Name, colNamePattern))
{
col.HeaderCell.Style.BackColor = backColor;
col.HeaderCell.Style.ForeColor = foreColor;
}
}
}
public const string TSV_PATH = @".\@@@DGV@@@.tsv";
/// <summary>
/// DGVデータTSV保存
/// </summary>
/// <param name="form"></param>
/// <param name="dgv"></param>
public static void SaveGridDataToTsv(Form form, DataGridView dgv)
{
var path = TSV_PATH.Replace("@@@DGV@@@", $"{form.Name}.{dgv.Name}");
try
{
using (StreamWriter sw = new StreamWriter(path, false, Encoding.UTF8))
{
foreach (DataGridViewRow row in dgv.Rows)
{
// 新規行(入力用の空行)はスキップ
if (row.IsNewRow) continue;
// 各セルの値をタブで結合
var cells = row.Cells.Cast<DataGridViewCell>().Select(c => c.Value?.ToString() ?? "");
sw.WriteLine(string.Join("\t", cells));
}
}
}
catch (Exception ex)
{
MessageBox.Show("DGVのTSV保存に失敗しました: " + ex.Message);
}
}
public static void LoadGridDataToTsv(Form form, DataGridView dgv)
{
var path = TSV_PATH.Replace("@@@DGV@@@", $"{form.Name}.{dgv.Name}");
if (!File.Exists(path)) return;
try
{
dgv.Rows.Clear();
string[] lines = File.ReadAllLines(path, Encoding.UTF8);
foreach (string line in lines)
{
if (string.IsNullOrWhiteSpace(line)) continue;
// タブで分割して行を追加
string[] values = line.Split('\t');
dgv.Rows.Add(values);
}
}
catch (Exception ex)
{
MessageBox.Show("DGVのTSVによる復元に失敗しました: " + ex.Message);
}
}
public static void SearchGrid(
DataGridView dgv,
string searchText,
bool forward)
{
if (string.IsNullOrEmpty(searchText)) return;
int rowCount = dgv.RowCount;
int colCount = dgv.ColumnCount;
// 現在のセルの位置を取得(選択されていなければ 0,0 から)
int startRow = dgv.CurrentCell?.RowIndex ?? 0;
int startCol = dgv.CurrentCell?.ColumnIndex ?? 0;
// 全セルをフラットなインデックスとして考えて計算
int totalCells = rowCount * colCount;
int startIndex = (startRow * colCount) + startCol;
for (int i = 1; i < totalCells; i++)
{
// forwardがtrueならプラス、falseならマイナス方向にずらす
int offset = forward ? i : -i;
int nextIndex = (startIndex + offset + totalCells) % totalCells;
int r = nextIndex / colCount;
int c = nextIndex % colCount;
DataGridViewCell cell = dgv[c, r];
if (cell.Value != null && cell.Value.ToString().Contains(searchText))
{
dgv.CurrentCell = cell;
return; // 見つかったら終了
}
}
MessageBox.Show("他には見つかりませんでしたにゃ!🐾");
}
}
}