Domanda

Ho un DataGridView non associato (in VS 2008), di cui una colonna contiene un percorso di file. Vorrei formattare la stringa utilizzando la classe TextRenderer sull'evento ColumnWidthChanged senza modificare effettivamente il valore sottostante. Il problema è che i contenuti della tabella vengono salvati quando il modulo viene chiuso e non voglio salvare il valore formattato. Penso di essere troppo in profondità per vedere la soluzione ovvia, quindi dipendo da voi ragazzi per sottolinearlo :-).

L'idea è di visualizzare questo:

C: \ Programmi \ Microsoft Visual Studio 8 \ SDK \ v2.0 \ Bin \ gacutil.exe

... come questo (a seconda della larghezza della colonna):

C: \ Programmi \ Microso & # 8230; \ gacutil.exe


Sembra che abbia parlato troppo presto. Sto ottenendo risultati molto strani da TextRenderer.MeasureText (). Se codifico il valore del percorso come " C: \ Documents and Settings \ jluce \ My Documents \ Download " arriva come C: \ Documents and Settings \ jluce \ M ... \ Downloads \ 0wnloads " ;. Se non lo codifico (come di seguito) viene ulteriormente danneggiato ogni volta che ridimensiono la colonna.

Ecco come appare dopo un ridimensionamento di coppia: Screenshot

Ecco cosa sto facendo attualmente.

  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;
    }
  }

Questo continua a diventare sempre più strano !!

Sono riuscito a risolvere il problema della stringa alterata scorrendo ogni carattere e rimuovendo quelli cattivi. Tuttavia, ora ho un problema ancora più folle. Una variabile locale che sto assegnando nel gestore eventi mantiene il suo valore tra le chiamate.

Ecco il codice pertinente:

     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;

Colonna di ridimensionamento per la prima volta (fare riferimento a # nei commenti sopra):

  1. Dopo questa riga Path contiene " " ;.
  2. Dopo questa riga, Path contiene una stringa così come appare sopra.
  3. Il percorso contiene il percorso del file troncato come dovrebbe (ad es. " C: \ Documents and Setti ... \ Download ")

Secondo ridimensionamento:

  1. Dopo questa riga Path contiene " " ;, come dovrebbe.
  2. Dopo questa riga, Path contiene " C: \ Documents and Set ... \ Downloads \ 0 Documents \ Downloads " ;, che era il valore non valido della precedente iterazione prima di eliminare i caratteri non validi (visto qui come '\ 0' ) !!
  3. Ora il percorso è FUBAR perché ho iniziato con una stringa sbagliata e continua a peggiorare.

Perché Path dovrebbe ricevere il valore non valido dalla precedente chiamata di funzione (dopo aver assegnato correttamente una stringa vuota!) quando gli sto assegnando esplicitamente un valore? !!!!!

È stato utile?

Soluzione

Il metodo

TextRenderer.MeasureText è un brutto - cambia la stringa effettiva passata come parametro, quindi cambia la stringa effettiva a cui fa riferimento DataGridView. In realtà rende una stringa .Net mutabile .

Sembra anche che questo ridicolo metodo non cambi l'effettivo Lunghezza della stringa, ma semplicemente sovrascrive uno dei caratteri con \ 0 per indicare la fine di la stringa (come stringhe con terminazione null nella semplice C). Sono cose divertenti!

Questo può avere un grave impatto sulla stabilità della tua app. Se si tiene conto del fatto che .Net utilizza string interning , puoi iniziare a ottenere tutti i tipi di risultati strani, poiché hai notato che le costanti della stringa non sembrano più costanti.

Il primo passo è creare una copia della tua stringa (una nuova istanza con gli stessi caratteri):

string Path = String.Copy(e.Value as string ?? "");

anziché

string Path = (string)Row.Cells[1].Value;

Ciò garantirà che, indipendentemente da ciò che TextRenderer , la stringa originale rimarrà invariata.

Dopodiché, è necessario eliminare il carattere null nella stringa modificata.

In questo modo:

if (Path.IndexOf('\0') >= 0)
   e.Value = Path.Substring(0, Path.IndexOf('\0'));
else
   e.Value = Path;

creerai una nuova istanza di una stringa pulita e modificata (lasciando la nostra copia temporanea Path senza riferimento per la garbage collection).

Altri suggerimenti

Devi usare l'evento CellFormatting per CAMBIARE il valore dato prima che venga stampato (il valore dell'oggetto originale non verrà modificato). Nel tuo caso, puoi verificare se è la colonna giusta verificando la variabile e.ColumnIndex e modificare il testo e.Value come ho fatto di seguito:

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; }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top