Question

J'ai un DataGridView non lié (dans VS 2008), dont une colonne contient un chemin de fichier. J'aimerais formater la chaîne à l'aide de la classe TextRenderer sur l'événement ColumnWidthChanged sans modifier réellement la valeur sous-jacente. Le problème est que le contenu de la table est enregistré à la fermeture du formulaire et que je ne souhaite pas enregistrer la valeur mise en forme. Je pense que je suis trop en profondeur pour voir la solution évidente. Je compte donc sur vous pour le signaler: -).

L'idée est d'afficher ceci:

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

... comme ceci (en fonction de la largeur de la colonne):

C: \ Program Files \ Microso & # 8230; \ gacutil.exe

Il semble que j'ai parlé trop tôt. Je reçois des résultats très étranges de TextRenderer.MeasureText (). Si je code la valeur du chemin d'accès sous la forme & C; C: \ Documents and Settings \ jluce \ Mes Documents \ Downloads " ça vient finit comme C: \ Documents and Settings \ jluce \ M ... \ Downloads \ 0wnloads " ;. Si je ne le code pas en dur (comme ci-dessous), il est de plus en plus corrompu à chaque fois que je redimensionne la colonne.

Voici à quoi cela ressemble après quelques redimensionnements: Capture d'écran

Voici ce que je suis en train de faire.

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

Cela ne cesse de se faire plus bizarre !!

J'ai réussi à résoudre le problème de la chaîne mutilée en parcourant chaque caractère et en supprimant les mauvais. Cependant, j'ai maintenant un problème encore plus fou. Une variable locale que j'attribue dans le gestionnaire d'événements conserve sa valeur entre les appels.

Voici le code correspondant:

     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;

Première colonne de redimensionnement (voir les # dans les commentaires ci-dessus):

  1. Après cette ligne, Path contient """.
  2. Après cette ligne, Path contient une chaîne juste comme elle apparaît ci-dessus.
  3. Path contient un chemin de fichier tronqué comme il se doit ("C: \ Documents and Setti ... \ Downloads")

Deuxième redimensionnement:

  1. Après cette ligne, Path contient """, comme il se doit.
  2. Après cette ligne, Path contient "C: \ Documents and Set ... \ Downloads \ 0 Documents \ Downloads", qui était la valeur non valide de la précédente itération avant que je ne supprime les caractères non valides (vus ici comme '\ 0 ') !!
  3. Le chemin est maintenant FUBAR car j'ai commencé avec une ficelle foutue et ça ne fait qu'empirer.

Pourquoi attribuer à Path la valeur non valide de l'appel de fonction précédent (après avoir correctement assigné une chaîne vide!) alors que je lui attribue explicitement une valeur? !!!!!

Était-ce utile?

La solution

La méthode

TextRenderer.MeasureText est une méchant - change la chaîne passée en paramètre, donc la chaîne référencée par DataGridView. Cela rend en fait une chaîne .Net mutable .

Il semble également que cette méthode ridicule ne modifie pas la longueur de la chaîne, mais remplace simplement l'un des caractères par \ 0 pour indiquer la fin de la chaîne. la chaîne (comme les chaînes terminées par null dans C non ordinaire). C'est des trucs marrants!

Cela peut avoir un impact sérieux sur la stabilité de votre application. Si vous prenez en compte que .Net utilise chaîne interning , vous pouvez commencer à obtenir toutes sortes de résultats étranges, car vous avez remarqué que vos constantes de chaîne ne semblent plus constantes.

La première étape consiste à créer une copie de votre chaîne (une nouvelle instance avec les mêmes caractères):

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

au lieu de

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

Ceci garantira que quel que soit le code TextRenderer , la chaîne d'origine restera inchangée.

Après cela, vous devez vous débarrasser du caractère nul dans la chaîne modifiée.

En procédant ainsi:

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

vous allez créer une nouvelle instance d'une chaîne propre et modifiée (en laissant notre copie Path temporaire non référencée pour le garbage collection).

Autres conseils

Vous devez utiliser l'événement CellFormatting pour CHANGER la valeur donnée avant son impression (la valeur de l'objet d'origine ne sera pas modifiée). Dans votre cas, vous pouvez vérifier si c'est la colonne de droite en vérifiant la variable e.ColumnIndex et modifier le texte de e.Value comme je l'ai fait ci-dessous:

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; }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top