Pergunta

Eu tenho um DataGridView não ligado (no vs 2008), da qual uma coluna contém um caminho de arquivo. Eu gostaria de formatar a string usando a classe Textrenderer no evento ColumnWidthChanged sem realmente modificar o valor subjacente. O problema é que o conteúdo da tabela é salvo quando o formulário é fechado e eu não quero salvar o valor formatado. Eu acho que estou muito profundo para ver a solução óbvia, então dependo de vocês para apontar :-).

A idéia é mostrar isso:

C: Arquivos de Programas Microsoft Visual Studio 8 SDK V2.0 bin gacutil.exe

... como isso (dependendo da largura da coluna):

C: Arquivos de programas microso… gacutil.exe


Parece que falei muito cedo. Estou obtendo alguns resultados muito estranhos do textrenderer.measureText (). Se eu codificar o valor do caminho como "C: Documentos e Configurações JluCe My Documents Downloads", ele aparece como C: Documentos e Configurações JluCe M ... Downloads 0Wnloads ". Se eu não for t Hardcode (como abaixo), ele é corrompido cada vez que redimenso a coluna.

Aqui está o que parece depois que alguns redimensionam:Captura de tela

Aqui está o que estou fazendo atualmente.

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

Isso continua ficando mais estranho !!

Consegui corrigir o problema da corda mutilada, iterando através de cada char e removendo os ruins. No entanto, agora eu tenho um problema ainda mais louco. Uma variável local que estou atribuindo no manipulador de eventos está mantendo seu valor entre as chamadas.

Aqui está o código relevante:

     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;

Primeira vez que a coluna de redimensionamento (consulte #está nos comentários acima):

  1. Após esse caminho de linha contém "".
  2. Após esse caminho de linha contém string exatamente como aparece acima.
  3. O caminho contém o caminho do arquivo truncado como deveria (ou seja, "C: Documents and Setti ... Downloads")

Segunda vez redimensionando:

  1. Após esse caminho de linha contém "", como deveria.
  2. Depois que esse caminho de linha contém "C: Documentos e Set ... Downloads 0 Documents Downloads", que era o valor inválido da iteração anterior antes de tirar os caracteres inválidos (vistos aqui como ' 0')! !
  3. Agora, o caminho é Fubar porque eu comecei com uma corda estragada e continua piorando.

Por que o caminho seria atribuído o valor inválido da chamada de função anterior (depois de atribuir corretamente uma string vazia!) Quando estou atribuindo explicitamente um valor a ela? !!!!!

Foi útil?

Solução

TextRenderer.MeasureText O método é a desagradável - Altera a string real passada como parâmetro, por isso está alterando a string real referenciada pelo DataGridView. Na verdade faz uma corda .NET mutável.

Parece também que esse método ridículo não muda o real Length da string, mas apenas substitui um dos personagens com \0 para indicar a extremidade da corda (como seqüências de cordas terminadas nulas na lisão C). Isso é algumas coisas engraçadas!

Isso pode ter um sério impacto na estabilidade do seu aplicativo. Se você levar em consideração que o .NET usa Internação de string, você pode começar a obter todos os tipos de resultados estranhos, pois notou que suas constantes de sequência não parecem mais constantes.

O primeiro passo é criar uma cópia da sua string (uma nova instância com os mesmos caracteres):

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

ao invés de

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

Isso garantirá que não importa o quê TextRenderer Faça, a string original permanecerá inalterada.

Depois disso, você precisa se livrar do caractere nulo na sequência modificada.

Ao fazer isso:

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

Você criará uma nova instância de uma string limpa e modificada (deixando nosso temporário Path copie não referenciado para coleta de lixo).

Outras dicas

Você precisa usar o evento de formação de células para alterar o valor fornecido antes de ser impresso (o valor do objeto original não será modificado). No seu caso, você pode verificar se é a coluna certa, verificando a variável e.columnindex e alterar o texto de E.Value, como eu fiz abaixo:

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; }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top