Substituindo DrawItem para a caixa de Listagem - a desmarcada itens não são redesenhados
-
17-09-2020 - |
Pergunta
Este é um C# aplicativo de área de trabalho.O DrawStyle
propriedade de meu ListBox
é definido como OwnerDrawFixed
.
O problema: Eu substituir DrawItem para desenhar o texto em diferentes fontes, e ele funciona.Mas quando eu começar a redimensionar o formulário em tempo de execução, o item selecionado é desenhado corretamente, mas os outros não são redesenhados, fazendo com que o texto procura corromper por não selecionados itens.
Aqui está o meu código:
private void listDevices_DrawItem(object sender, DrawItemEventArgs e)
{
e.DrawBackground();
string textDevice = ((ListBox)sender).Items[e.Index].ToString();
e.Graphics.DrawString(textDevice,
new Font("Ariel", 15, FontStyle.Bold), new SolidBrush(Color.Black),
e.Bounds, StringFormat.GenericDefault);
// Figure out where to draw IP
StringFormat copy = new StringFormat(
StringFormatFlags.NoWrap |
StringFormatFlags.MeasureTrailingSpaces
);
copy.SetMeasurableCharacterRanges(new CharacterRange[] {new CharacterRange(0, textDevice.Length)});
Region[] regions = e.Graphics.MeasureCharacterRanges(
textDevice, new Font("Ariel", 15, FontStyle.Bold), e.Bounds, copy);
int width = (int)(regions[0].GetBounds(e.Graphics).Width);
Rectangle rect = e.Bounds;
rect.X += width;
rect.Width -= width;
// draw IP
e.Graphics.DrawString(" 255.255.255.255",
new Font("Courier New", 10), new SolidBrush(Color.DarkBlue),
rect, copy);
e.DrawFocusRectangle();
}
listDevices.Items.Add("Device001");
listDevices.Items.Add("Device002");
Além disso, o item que está desenhado corretamente (a selecionada) é cintilação no formulário de redimensionamento.Nada demais, mas se alguém sabe o porquê....tnx
Solução
Coloque o seguinte código no evento Resize:
private void listDevices_Resize(object sender, EventArgs e) {
listDevices.Invalidate();
}
Isso deve fazer de tudo para ser redesenhado.
Para parar a cintilação, você tem a memória intermédia dupla.
Para fazer isso, crie uma nova classe derivada de caixa de Listagem, e coloque o seguinte no construtor:
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
Ou apenas cole-o em um arquivo de código:
using System.Windows.Forms;
namespace Whatever {
public class DBListBox : ListBox {
public DBListBox(): base() {
this.DoubleBuffered = true;
// OR
// this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
}
}
}
Substituir "o que" com o espaço de nomes usa seu projeto, ou fazer algo mais útil.Depois de compilar, você deve ser capaz de adicionar um DBListBox no designer de formulário.
Outras dicas
Eu reproduzem o problema.Há vários erros no código, o nome de tipo de letra é "Arial", você não deve ajustar rect.Largura, não se esqueça de chamar Dispose() na letra, pincéis e regiões.Mas eles não explicam o comportamento.Há algo de errado com a área de recorte que impede que o texto seja atualizado corretamente.Não vejo onde isso ocorre, o objeto Graphics estado está bem.
Gráficos.DrawString() é muito conturbado método, você deve realmente evitar.Todos os controlos de Formulários do Windows, incluindo a caixa de Listagem, use TextRenderer.DrawText().O que resolve o problema quando eu usá-lo.Eu sei medição é mais difícil, você pode trabalhar em torno disso, apresentar o endereço IP fixo deslocamento.Parece muito melhor, eles vão de linha em uma coluna que a forma.
Ele pisca, porque você usa e.DrawBackground().Que apaga o texto existente, você deve desenhar o texto para a direita de volta a ele.Eu não acho que a memória intermédia dupla vai corrigir isso, você iria ter que tirar o item inteiro, assim você não tem que desenhar o plano de fundo.Complicado se você não puder obter o tamanho exato do texto com a fonte grande, uma solução é desenhada em um mapa de bits em primeiro lugar.