2

バインドされていない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:\ DocumentsandSettings \ jluce \ MyDocuments \ 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;

初めて列のサイズを変更する(上記のコメントの#を参照):

  1. この行の後、パスには「」が含まれています。
  2. この行の後に、上記のようにPathに文字列が含まれます。
  3. パスには、必要に応じて切り捨てられたファイルパスが含まれています(つまり、「C:\ Documents and Setti ... \ Downloads」)

2回目のサイズ変更:

  1. この行の後に、必要に応じてパスに「」が含まれます。
  2. この行の後、パスには「C:\ Documents and Set ... \ Downloads \ 0 Documents \ Downloads」が含まれています。これは、無効な文字(ここでは「\ 0」として表示)を削除する前の前の反復からの無効な値でした。 !!
  3. ひもをねじ込んだ状態から始めたので、パスはFUBARになりましたが、悪化し続けています。

明示的に値を割り当てているのに、(空の文字列を正しく割り当てた後!)前の関数呼び出しから無効な値がPathに割り当てられるのはなぜですか?!!!!!

4

2 に答える 2

2

TextRenderer.MeasureTextメソッドは厄介なものです。パラメータとして渡される実際の文字列を変更するため、DataGridViewによって参照される実際の文字列を変更します。実際には、.Net文字列を変更可能にします。

また、このばかげた方法はLength文字列の実際を変更せず、文字列の終わりを示すために文字の1つを上書きするだけの\0ようです(プレーンCのnullで終了する文字列のように)。それは面白いものです!

これは、アプリの安定性に深刻な影響を与える可能性があります。.Netが文字列インターンを使用していることを考慮に入れると、文字列定数が一定ではなくなっていることに気付いたので、あらゆる種類の奇妙な結果を得ることができます。

最初のステップは、文字列のコピー(同じ文字を持つ新しいインスタンス)を作成することです。

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ガベージコレクションのために一時的なコピーを参照しないままにします)。

于 2009-10-23T16:03:14.980 に答える
2

指定された値を印刷する前に変更するには、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; }
}
于 2009-10-22T23:01:07.643 に答える