基になる値を変更せずにDataGridViewセルをフォーマットしますか?
-
05-07-2019 - |
質問
バインドされていないDataGridView(VS 2008)があり、その1列にファイルパスが含まれています。実際に基になる値を変更せずに、ColumnWidthChangedイベントでTextRendererクラスを使用して文字列を書式設定したいと思います。問題は、フォームを閉じたときにテーブルの内容が保存され、フォーマットされた値を保存したくないことです。明らかな解決策を見るには深すぎると思うので、それを指摘するのは皆さんに依存しています:-)。
アイデアはこれを表示することです:
C:\ Program Files \ Microsoft Visual Studio 8 \ SDK \ v2.0 \ Bin \ gacutil.exe
...これとして(列の幅による):
C:\ Program Files \ Microso… \ gacutil.exe
話しすぎたようです。 TextRenderer.MeasureText()から非常に奇妙な結果が得られています。パス値を" C:\ Documents and Settings \ jluce \ My Documents \ Downloads"としてハードコーディングした場合として来る C:\ Documents and Settings \ jluce \ M ... \ Downloads \ 0wnloads"。 (以下のように)ハードコーディングしないと、列のサイズを変更するたびにさらに破損します。
カップルのサイズ変更後の外観は次のとおりです。 スクリーンショット
現在、私がやっていることです。
if (e.ColumnIndex == 1)
{
foreach (DataGridViewRow Row in mappingsDataGrid.Rows)
{
string Path = (string)Row.Cells[1].Value;
Path = Path.Trim();
TextRenderer.MeasureText(Path, e.CellStyle.Font,
new Size(mappingsDataGrid.Columns[e.ColumnIndex].Width, Row.Height),
TextFormatFlags.ModifyString | TextFormatFlags.PathEllipsis);
e.Value = Path;
}
}
これはただ奇妙になり続けています!!
各文字を繰り返し処理し、不良文字を削除することで、文字列の破損の問題を解決できました。しかし、今ではさらにひどい問題に直面しています。イベントハンドラーで割り当てているローカル変数は、呼び出し間で値を保持しています。
関連するコードは次のとおりです。
string Path = ""; // <-- #1
Path = "C:\\Documents and Settings\\jluce\\My Documents\\Downloads"; // <-- #2
TextRenderer.MeasureText(Path, Row.Cells[1].Style.Font,
new Size((mappingsDataGrid.Columns[e.Column.Index].Width), Row.Height),
TextFormatFlags.ModifyString | TextFormatFlags.PathEllipsis);
// Left out code that strips invalid chars
Row.Cells[1].Value = Path; // <-- #3
Path = null;
最初の列のサイズ変更(上記のコメントの#を参照):
- この行の後、パスには&quot;&quot;が含まれます。
- この行の後、パスには上記の文字列が含まれます。
- パスには、切り捨てられたファイルパスが含まれている必要があります(つまり、&quot; C:\ Documents and Setti ... \ Downloads&quot;)
2回目のサイズ変更:
- この行の後、Pathには&quot;&quot;が含まれているはずです。
- この行の後、パスには&quot; C:\ Documents and Set ... \ Downloads \ 0 Documents \ Downloads&quot;が含まれます。これは、無効な文字を削除する前の前回の反復からの無効な値でした(ここでは '\ 0 ')!!
- 現在、ねじれた紐から始めたので、パスはFUBARになりますが、悪化し続けています。
明示的に値を割り当てているときに、(空の文字列を正しく割り当てた後に)前の関数呼び出しから無効な値がPathに割り当てられるのはなぜですか?!!!!!
解決
TextRenderer.MeasureText
メソッドは厄介なもの-パラメーターとして渡される実際の文字列を変更するため、DataGridViewによって参照される実際の文字列を変更します。実際には、.Net文字列を mutable にします。
このとんでもない方法は、文字列の実際の Length
を変更せず、単に \ 0
で文字の1つを上書きして、文字列(プレーンCのヌル終了文字列など)。それは面白いものです!
これは、アプリの安定性に深刻な影響を与える可能性があります。 .Netが string interning 、文字列定数が一定ではないことに気付いたように、あらゆる種類の奇妙な結果を得ることができます。
最初のステップは、文字列のコピー(同じ文字を持つ新しいインスタンス)を作成することです:
string Path = String.Copy(e.Value as string ?? "");
の代わりに
string Path = (string)Row.Cells[1].Value;
これにより、 TextRenderer
の動作に関係なく、元の文字列は変更されません。
その後、変更された文字列のヌル文字を取り除く必要があります。
これにより:
if (Path.IndexOf('\0') >= 0)
e.Value = Path.Substring(0, Path.IndexOf('\0'));
else
e.Value = Path;
クリーンで変更された文字列の新しいインスタンスを作成します(ガベージコレクションでは参照されない一時的な Path
コピーを残します)。
他のヒント
CellFormattingイベントを使用して、指定された値を印刷する前に変更する必要があります(元のオブジェクトの値は変更されません)。あなたのケースでは、e.ColumnIndex変数を確認して正しい列かどうかを確認し、以下のようにe.Valueテキストを変更できます。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
dataGridView1.DataSource = new List<Person>(new Person[] { new Person() { Name = "André", Adress = "Brazil" } });
}
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
e.Value = e.Value + " modified";
}
}
class Person
{
public String Name { get; set; }
public String Adress { get; set; }
}