terça-feira, 16 de abril de 2024
Aprenda a Evitar Memory Leaks no .NET com Dispose e Blocos Using
Os memory leaks são como fantasmas assombrando os
desenvolvedores de software. Eles podem se esconder silenciosamente em nossos
códigos, consumindo recursos preciosos e prejudicando o desempenho do
aplicativo. No ambiente .NET, a gestão de memória é parcialmente automatizada
pelo coletor de lixo (garbage collector), mas mesmo assim, é responsabilidade
do desenvolvedor garantir a liberação adequada de recursos não gerenciados.
Felizmente, o .NET oferece algumas ferramentas poderosas para lidar com isso, como
o método Dispose() e os blocos using.
O Que São Memory Leaks?
Um memory leak ocorre quando um programa aloca memória
dinamicamente repetidamente, mas não libera essa memória quando não é mais
necessária. Isso pode acontecer por várias razões, mas é especialmente comum
quando trabalhamos com recursos não gerenciados, como arquivos, conexões de
banco de dados e objetos COM.
A Importância do Método Dispose()
O método Dispose() é uma parte fundamental do padrão
de design "Dispose pattern" no .NET. Ele é usado para liberar
explicitamente os recursos não gerenciados usados por um objeto. Ao implementar
a interface IDisposable e chamar o método Dispose(), os
desenvolvedores podem garantir que os recursos sejam liberados assim que não
forem mais necessários.
Usando Blocos Using para Garantir a Liberação de Recursos
Os blocos using no C# fornecem uma maneira
conveniente de garantir que os objetos que implementam IDisposable sejam
liberados corretamente, mesmo se ocorrerem exceções no código. Um bloco using
garante que o método Dispose() seja chamado automaticamente quando o
escopo do bloco é concluído.
Exemplo Prático
Vamos examinar um trecho de código e explorar como podemos
melhorá-lo para garantir uma gestão mais robusta de recursos no ambiente .NET.
No código acima, estamos lidando com uma operação de leitura
de dados de um banco SQLite e exibindo-os em um DataGridView. Pode ser
que vocês já estejas familiarizado com códificação
parecida. No entanto, há alguns problemas de gestão de recursos que precisamos
resolver:
1. Gestão de Conexão com o Banco de Dados
O objeto SQLiteConnection precisa ser aberto e
fechado corretamente para evitar vazamentos de recursos. Vamos usar um bloco using
para garantir que a conexão seja fechada automaticamente quando não for mais
necessária.
2. Limpeza de Recursos em Caso de Exceção
Se ocorrer uma exceção durante a execução do código dentro
do bloco using, precisamos garantir que os recursos sejam liberados
corretamente. Vamos mover a definição do objeto DataTable para dentro do
bloco using e usar o método Dispose() para liberar o leitor e o
comando em caso de exceção.
Conclusão
Lidar com memory leaks no .NET é crucial para manter a
estabilidade e o desempenho dos aplicativos. Utilizar corretamente o método Dispose()
e os blocos using é uma prática recomendada para garantir a liberação
adequada de recursos não gerenciados. Ao melhorar a gestão de recursos em nosso
código, garantimos que ele seja mais robusto, eficiente e menos propenso a
problemas como memory leaks. Utilizando blocos using para objetos que
implementam IDisposable, lidamos adequadamente com a liberação de
recursos. Ao seguir essas práticas, podemos criar aplicativos mais estáveis e
de alta qualidade no ambiente .NET. Adotar essas práticas desde o início do
desenvolvimento, os desenvolvedores podem evitar muitas dores de cabeça no
futuro e garantir uma experiência de usuário mais suave.
sexta-feira, 31 de agosto de 2018
Como exportar Crystal Report para PDF e Excel (código completo)
Vamos aprender, de forma rápida, como exportar um relatório de Crystal Report para os formatos PDF e Excel. Como exemplo vou pegar o projecto que fizemos no post anterior. Clica aqui para ver.Adicione os botões "Exportar PDF" e "Exportar Excel" no formulário para exportar o relatório.
Para o botão "Exportar PDF" coloque o seguinte código:
Para o botão "Exportar Excel" coloque o seguinte código:
Código completo deste projecto.
public partial class FormPaises : Form
{
public FormPaises()
{
InitializeComponent();
}
Reports.ReportPaises2 cr = new Reports.ReportPaises2();
private List<Pais> GetListaPaises()
{
List<Pais> Paises = new List<Pais>
{
new Pais(1, "Angola"),
new Pais(2, "Brasil"),
new Pais(3, "Portugal"),
new Pais(6, "Moçambique"),
new Pais(7, "Cabo-Verde"),
new Pais(8, "Namibia")
};
return Paises;
}
private void FormPaises_Load(object sender, EventArgs e)
{
crystalReportViewer1.ReportSource = cr;
cr.SetDataSource(GetListaPaises());
}
private void btnExportToPDF_Click(object sender, EventArgs e)
{
SaveFileDialog dialog = new SaveFileDialog();
dialog.Filter = "Arquivo PDF|*.pdf";
string nomeArquivo="";
if(dialog.ShowDialog()== DialogResult.OK)
{
nomeArquivo = dialog.FileName;
cr.ExportToDisk(ExportFormatType.PortableDocFormat, nomeArquivo);
}
}
private void btnExportToExcel_Click(object sender, EventArgs e)
{
SaveFileDialog dialog = new SaveFileDialog();
dialog.Filter = "Arquivo Excel|*.xls";
string nomeArquivo = "";
if (dialog.ShowDialog() == DialogResult.OK)
{
nomeArquivo = dialog.FileName;
cr.ExportToDisk(ExportFormatType.Excel, nomeArquivo);
}
}
}
Como criar um relatório CrystalReport sem banco de dados
A um tempo tive problemas com as conexões do crystal report. Quando passava a aplicação para outros computadores tinha que trocar também a conexão, porem muitas vezes esquecia de fazer esse processo e ficava horas e horas para descobrir onde estava o problema. Por isso optei por usar os crystal report sem conexão directa a base de dados.
O que vamos ver é pequeno exemplo de como criar um relatório de Lista de Países com o Crystal Reports a partir de uma lista de objectos sem ter uma banco de dados.
Passo 1
Certifique-se de ter Crystal Report para o Visual Studio instalado.Passo 2
Cria um novo projecto WinForm. Neste exemplo criei um projecto com nome TesteCrystalSemDB. A seguir, cria uma classe País como o seguinte:public class Pais
{
public Pais(int codigo,string nome)
{
this.Codigo = codigo;
this.NomePais = nome;
}
public int Codigo { get; set; }
public string NomePais { get; set; }
}
Passo 3
Adicione um novo formulário com o nome FormPaises, e adicione o seguinte método:
private List<Pais> GetListaPaises()
{
List<Pais> Paises = new List<Pais>
{
new Pais(1, "Angola"),
new Pais(2, "Brasil"),
new Pais(3, "Portugal"),
new Pais(6, "Moçambique"),
new Pais(7, "Cabo-Verde"),
new Pais(8, "Namibia")
};
return Paises;
}
Passo 4
Adicione um DataSet. Nomeia-o por DataSet1 como na figura abaixo:Dentro da DataSet adicione uma DataTable com o nome de Pais, e cria as colunas com os mesmos nome dos atributos da classe Pais. ( Esse é o maior segredo ;). Confirma na figura acima.
Passo 5
Adicione ao projecto um Crystal Report e nomeio-o por ReportPaises2, clique em Add.
Aparecerá uma caixa como a que se segui, as opeções criar um nome documento de crystal report, escolha a segunda, Relatório em Branco e clica OK.
Passo 6

No assistente, expande Dados de Projecto > Conjuntos de Dados ADO.NET > TesteCrystalSemDB.DataSet1e seleccione a DataTable Pais.
Passo 7
Volte para o formulário FormPaises, vai à ToolBox, escolha o CrystalReportViewer, coloque-o ao formulário e nomeia-o por crystalReportViewer1.
Selecione este novo componente e (1) no seu canto superior direito dê um clique para ver a lista de propriedades, (2) clique em "Escolher um Crystal Report, (3) Selecione o relatorio que criamos "ReportPaises2", (4) clique em OK.
private void FormPaises_Load(object sender, EventArgs e)
{
Reports.ReportPaises2 cr = new Reports.ReportPaises2();
crystalReportViewer1.ReportSource = cr;
cr.SetDataSource(GetListaPaises());
}
Pronto, o relatório está feito, basta pressionar F5 para testar.
Bonus
A propriedade SetDataSource do CrystalReport pode receber qualquer colecção de dados. Por isso aproveita essa propriedade colocar a tua fonte da dados. Como eu disse no inicio deste post, não acho viável os dados serem dependentes da conexão do Crystal Report.sexta-feira, 27 de julho de 2018
Como definir a resolução do monitor com o C#
Tive dificuldade em definir uma resolução de tela dinâmica quando estava fazendo um aplicativo. Eu presumo que a maioria de nós tenha acontecido conosco ou tenha enfrentado esses tempos em algum lugar ao longo de nosso ciclo de vida de engenharia. Porque, como todos sabemos, a resolução da tela do usuário pode não ser a mesma da tela do ambiente de desenvolvimento.Neste post vou entregar o que eu encontrei como uma solução para o desafio discutido.
Então vamos ver:
- Como obter a resolução do monitor do usuário.
- Como alterar a resolução do monitor do usuário para produto compatível
- Como proteger a resolução do monitor do usuário.
Como obter a resolução do monitor do usuário
O acesso à tela do usuário está sendo facilitado pela classe Screen, que é fornecida junto com a estrutura .NET. E pode acessar a resolução da tela do usuário atual por meio de uma propriedade Screen.PrimaryScreen que é estática disponível na classe Screen:
public static Screen PrimaryScreen {get;}
A propriedade acima mencionada é somente leitura e retorna um tipo Screen. E a lógica abaixo mostra como usar o tipo Screen para acessar a resolução da tela do usuário:
Screen screen = Screen.PrimaryScreen;
int S_width=screen.Bounds.Width;
int S_height=screen.Bounds.Height;
Como alterar a resolução do monitor do usuário para produto compatível
Antes de seguir em direção ao nosso próximo objetivo, deixe-me falar sobre a parte não gerenciada dessa implementação. Ao contrário das linguagens tradicionais, a estrutura .NET mantém uma etapa distinta enquanto aproveita o código gerenciado e não gerenciado. Pessoalmente, quando escrevi este artigo, nunca encontrei nenhum código gerenciado que faça esse tratamento de resolução. E isso é o que me fez pensar em explorar algumas APIs do Win32.
Como o escopo deste artigo está limitado ao código gerenciado, não discutirei nada sobre código não gerenciado. Mas, apesar disso, podemos usar o atributo DllImport para ler a definição de código não gerenciado em seu ambiente gerenciado. Neste caso, estaremos usando a API User32.dll, que facilita a resolução dinâmica e possui duas funções relacionadas à alteração da resolução da tela.
- EnumDisplaySettings
- ChangeDisplaySettings
class User32
{
[DllImport("user32.dll")]
public static extern int EnumDisplaySettings (string deviceName, int modeNum, ref DEVMODE devMode );
[DllImport("user32.dll")]
public static extern int ChangeDisplaySettings(
ref DEVMODE devMode, int flags);
public const int ENUM_CURRENT_SETTINGS = -1;
public const int CDS_UPDATEREGISTRY = 0x01;
public const int CDS_TEST = 0x02;
public const int DISP_CHANGE_SUCCESSFUL = 0;
public const int DISP_CHANGE_RESTART = 1;
public const int DISP_CHANGE_FAILED = -1;
}
Como sabemos, o [DllImport("user32.dll")] é um trabalho explícito antes de injetar uma implementação não gerenciada em nosso ambiente gerenciado.
public static extern int EnumDisplaySettings(string deviceName, int modeNum, ref DEVMODE devMode);
DEVMODE é uma estrutura explicada na documentação da plataforma, bem como incluída no Visual Studio .NET. A estrutura é definida em C#, por isso não se preocupar!
[StructLayout(LayoutKind.Sequential)]
public struct DEVMODE
{
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=32)]
public string dmDeviceName;
public short dmSpecVersion;
public short dmDriverVersion;
...
}
Você pode dar uma olhada no código-fonte clicando aqui e aplicar essa lógica a qualquer evento desejado.
Esteja ciente de que, os tipos têm o tamanho certo e que as seqüências de comprimento fixo são apropriadamente definida. Neste caso, WORD mapeia para short, DWORD para int e short permanece como short.
DEVMODE dm = new DEVMODE();
dm.dmDeviceName = new String(new char[32]);
dm.dmFormName = new String(new char[32]);
dm.dmSize = (short)Marshal.SizeOf (dm);
if (0 !=User32.EnumDisplaySettings(null,User32.ENUM_CURRENT_SETTINGS,ref dm))
{
Neste ponto, a estrutura DEVMODE será decorado com as configurações padrão e pode modificá-la em qualquer instância.
dm.dmPelsWidth = iWidth;
dm.dmPelsHeight = iHeight;
int iRet = User32.ChangeDisplaySettings(ref dm, User32.CDS_UPDATEREGISTRY);
O bloco de código fechado faz isso um pouco diferente de lidar com várias condições de erro. Gostaria de incentivá-lo a olhar para o arquivo fonte completo e ver o que ele faz. Isso é tudo que existe para isso.
Como proteger a resolução de tela do usuário
Finalmente, antes de continuarmos, é nossa responsabilidade salvaguardar a resolução de tela padrão de um usuário. Para fazer isso, você pode ter que usar alguns membros ou classes estáticas para manter a resolução da tela do usuário e retê-la quando concluir a execução.Bonus - O código-fonte completo
quarta-feira, 30 de maio de 2018
Como arraste e solte uma imagem de uma pasta para picturebox com C#
using System.Threading;
using System.Diagnostics;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Diagnostics;
public partial class Form1 : Form
{
protected Image image;
protected Thread getImageThread public Form1()
{
InitializeComponent();
}
string filename;
validData = GetFilename(out filename, e);
if (validData)
{
path = filename;
getImageThread = new Thread(new ThreadStart(LoadImage));
getImageThread.Start();
e.Effect = DragDropEffects.Copy;
}
else
e.Effect = DragDropEffects.None;
}
private bool GetFilename(out string filename, DragEventArgs e)
{
bool ret = false;
filename = String.Empty;
if ((e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy)
Array data = ((IDataObject)e.Data).GetData("FileDrop") as Array;
if (data != null)
{
if ((data.Length == 1) && (data.GetValue(0) is String))
{
filename = ((string[])data)[0];
string ext = Path.GetExtension(filename).ToLower();
if ((ext == ".jpg") || (ext == ".png") || (ext == ".bmp"))
{
ret = true;
}
}
}
}
return ret;
}
if (validData)
{
while (getImageThread.IsAlive)
{
Application.DoEvents();
Thread.Sleep(0);
}
pictureBox1.Image = image;
}
}
image = new Bitmap(path);
}
}
}
quarta-feira, 16 de maio de 2018
Como usar o ColorDialog no C#
Um controle ColorDialog é usado para selecionar uma cor das cores disponíveis e também definir cores personalizadas. Uma caixa de diálogo de cores típica se parece com a Figura 1, onde você pode ver que há uma lista de cores sólidas básicas e que há uma opção para criar cores personalizadas.

figura 1

Figura 2

Figura 3

Figura 4

Figura 5

Figura 6

Figura 7
Um controle ColorDialog permite que os usuários iniciem o Diálogo de Cor do Windows e permitam que eles selecionem uma cor sólida ou criem uma cor personalizada a partir das cores disponíveis. Neste artigo, discutimos como usar um diálogo de cores do Windows e definir suas propriedades em um aplicativo do Windows Forms.














