Uma maneira universal de personalizar a aparência de um aplicativo WinForms (usando o exemplo do FAQ.Net)

1. Introdução


Depois de postar o primeiro artigo sobre meu aplicativo FAQ.Net (programa de anotações do Windows) , apareceram os primeiros usuários que gostariam de continuar desenvolvendo seu programa de anotações.

Para aumentar o interesse dos usuários, surgiu uma idéia para aumentar sua atratividade, ajustando a cor e a fonte.

Requisitos para personalizar a aparência do aplicativo


  1. armazenar e carregar propriedades de componentes individuais em um arquivo XML
  2. o usuário deve ter uma ferramenta simples para personalizar a aparência
  3. a lista de componentes personalizados deve se expandir de maneira muito simples (em uma linha de código)
  4. ao alterar o valor de uma propriedade, o usuário deve ver imediatamente as alterações no formulário
  5. deve haver um botão de cancelamento que permita reverter todas as alterações

Resultado do trabalho


Janela de aparência:



Antes e depois das configurações de aparência:



Para resolver o problema é necessário


  1. use o componente PropertyGridEx para exibir e alterar as propriedades do componente
  2. crie uma classe CustomDesignControl para a conveniência de armazenar propriedades em XML
  3. crie um formulário MainForm, no qual mudaremos a aparência
  4. crie um formulário AppSettingsForm, no qual personalizaremos a aparência do MainForm
  5. crie a classe SettingsXml para conveniência de XML

A função de desfazer alterações na aparência


Para implementar a abolição das alterações na aparência (parágrafo 5 dos requisitos), decidi encontrar uma maneira universal de clonar as propriedades dos componentes que serão criados na memória e substituir os componentes exibidos.

Clonando objetos:

public static class ControlExtensions { public static T Clone<T>(T controlToClone) where T : Control { PropertyInfo[] controlProperties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance); T instance = Activator.CreateInstance<T>(); RichTextBox rtb = new RichTextBox(); foreach (PropertyInfo propInfo in controlProperties) { if (propInfo.Name == "Parent") continue; if (propInfo.CanWrite) { if (propInfo.Name != "WindowTarget") { propInfo.SetValue(instance, propInfo.GetValue(controlToClone, null), null); } } } return instance; } 

Copiei o código, removi propriedades desnecessárias que não precisam ser salvas, deixando as cores e a fonte.
Após a verificação do código, as deficiências desse método foram imediatamente reveladas:

  1. a conversão de qualquer controle para a classe Control é usada, o que significa que metade das propriedades pode ser perdida (por exemplo, o componente DataGridView é herdado da classe Control, mas possui seu próprio conjunto adicional de propriedades)
  2. ao clonar um componente, algumas propriedades (por exemplo: a cor da fonte na célula DataGridView) não são clonadas, mas criam links para o componente clonado (talvez seja porque a propriedade é usada com suas propriedades internas e precisa ser tratada de maneira diferente).

Ele começou a experimentar no segundo parágrafo, a fim de obter com precisão a clonagem da propriedade.
Para fazer isso, crie um objeto do tipo desejado com o novo operador.

 DataGridView dgvClone = new DataGridView(); 

Sem sucesso, o componente não pôde reverter as alterações.

Tentei criar a propriedade em si com o novo operador e definir o valor usando o método SetValue:

 propInfo.SetValue(_controls[i], propInfo.GetValue(_controlsBeforeChange[i], null), null); 

E este método não deu resultado. Quando um valor de propriedade é alterado em um componente, ele é atualizado automaticamente no componente clonado.

Não procurei mais outros métodos e retornei a alteração simplesmente reiniciando o aplicativo com a capacidade de salvar o documento de trabalho ou cancelar a reinicialização. Isso permitiu economizar significativamente a memória do aplicativo, pois não é necessário criar clones de objetos.

Exemplo de aplicativo com customização de aparência


Por precaução, preparei um código pronto para que todos possam verificar e possivelmente modificar a função de cancelar alterações na aparência sem reiniciar o aplicativo e nos informar sobre o problema nos comentários.
É necessário garantir que, ao clicar no botão "Autoteste", o componente DataGridView tenha um plano de fundo cinza e a fonte das células seja pequena.



Faça o download do aplicativo para Windows FAQ.Net (gratuito):

(x64) yadi.sk/d/sq3g4NOD3Zt7ZY
(x86) yadi.sk/d/NKXeyUWH3Zt8PQ

Grupo VK
Código fonte FAQ.Net

Conclusão


Espero que em muitos aplicativos WinForms, graças a este artigo, o usuário final tenha a oportunidade de personalizar a interface de acordo com seu gosto e cor.

Source: https://habr.com/ru/post/pt474104/


All Articles