ReadOnly NumericUpDown
O controlo NumericUpDown, na propriedade ReadOnly, não tem um comportamento perfeito no seu funcionamento, pois embora esteja definido como ReadOnly, é possível alterar os números através das setas (Up e Down).
Uma das formas de resolver este problema é criar um novo controlo, que herda o controlo base, e que faz o Override ao UpButton e DownButton de modo a ignorar as setas, caso a propriedade ReadOnly esteja definida.
Como a definição desta propriedade altera também a cor de fundo (BackColor), foi criada uma Shadow Property para não fazer esta alteração e podes personalizar o controlo a gosto.
O resultado é esta classe que após compilada ficará disponível na Toolbox
Class ReadOnlyNumericUpDown
Inherits NumericUpDown
Private m_ReadOnly As Boolean
'''<summary>
''' Cria uma propriedade para definir o NumericUpDown como ReadOnly
''' e como já existe uma propriedade com este nome é necessário criar
''' uma Shadows Property. Além disso como é uma palavra reservada tem
''' de ser colocada entre chavetas rectas []
'''</summary>
Public Shadows Property [ReadOnly]() As Boolean
Get
Return m_ReadOnly
End Get
Set(ByVal value As Boolean)
m_ReadOnly = value
End Set
End Property
'''<summary>
''' Ao ser carregado no botão para cima e se for ReadOnly ignora a acção
'''</summary>
'''<remarks></remarks>
Public Overrides Sub UpButton()
If Not Me.ReadOnly Then
MyBase.UpButton()
End If
End Sub
'''<summary>
''' Ao ser carregado no botão para baixo e se for ReadOnly ignora a acção
'''</summary>
'''<remarks></remarks>
Public Overrides Sub DownButton()
If Not Me.ReadOnly Then
MyBase.DownButton()
End If
End Sub
'''<summary>
''' Ao ser pressionada uma tecla e se for ReadOnly ignora a acção
''' </summary>
''' <remarks></remarks>
Protected Overrides Sub OnKeyDown(ByVal e As System.Windows.Forms.KeyEventArgs)
If Not Me.ReadOnly Then
MyBase.OnKeyDown(e)
Else
e.SuppressKeyPress = True
End If
End Sub
End Class
Alterar o Wallpaper do Sistema Operativo
A alteração do wallpaper (ambiente de trabalho) do sistema operativo é sempre uma acção muito utilizada e que muitos aproveitam para criar pequenos aplicativos para o fazer (embora já existam várias ferramentas disponíveis).
A alteração do wallpaper pode-se fazer muito simplesmente através da API SystemParametersInfo. Um dos problemas que normalmente se vê em alguns códigos para alterar o wallpaper do computador, é a utilização de ficheiros *.jpg, *.png, etc, sem a conversão para um formato bmp (que o sistema aceita).
Fica um exemplo de como fazer esta alteração:
' Declaração da API que irá alterar o wallpaper
Private Declare Function SystemParametersInfo Lib "user32"Alias"SystemParametersInfoA"(ByVal uAction As Integer, ByVal uParam As Integer, ByVal lpvParam As String, ByVal fuWinIni As Integer) As Integer
' Definição das constantes
Private Const SPI_SETDESKWALLPAPER = 20
Private Const SPIF_UPDATEINIFILE = &H1
'''<summary>
''' Muda o wallpaper do computador
'''</summary>
'''<param name="imagePath">Endereço completo da imagem</param>
'''<remarks></remarks>
Private Sub SetWallpaper(ByVal imagePath As String)
' Verifica se o ficheiro existe
If Not IO.File.Exists(imagePath) Then
Throw New Exception("O ficheiro indicado não existe!")
End If
Try
Dim imgName As String
' Caso o ficheiro indicado não seja um *.bmp é necessário
' converter para tal, de modo a que este funcione
If IO.Path.GetExtension(imagePath) <> ".bmp"Then
' Cria o ficheiro *.bmp
imgName = IO.Path.ChangeExtension(imagePath, "bmp")
' Cria uma nova image e grava como *.bmp
Using bm AsBitmap = Image.FromFile(imagePath)
bm.Save(imgName, Imaging.ImageFormat.Bmp)
End Using
Else
imgName = imagePath
End If
' Define o novo wallpaper
SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, imgName, _
SPIF_UPDATEINIFILE)
Catch ex AsException
Throw New Exception(ex.Message)
End Try
End Sub
Para alterar o wallpaper é apenas necessário fazer:
SetWallpaper("c:\imagem.jpg")
PS: Como sempre, qualquer dúvida, comentário ou correcção ao artigo é sempre bem vinda!
Windows Presentation Foundation (WPF) permite criar aplicações muito ricas, muito versáteis e com muitos recursos visuais. Uma aplicação que usa WPF é normalmente composta por duas partes: um arquivo XML com características especiais chamado XAML (eXtended Aplication Markup Language, pronuncia-se “zémel”), e um código .NET (que pode ser escrito numa linguagem compatível como o VB.net ou C#).
Mas nem todos gostam de WPF para criar aplicações, até porque é necessário um processo de aprendizagem significativo, quer pelo XAML quer pela arquitectura geral de funcionamento.
Mas porquê não utilizar as potencialidades do WPF em Windows Forms?
É bastante simples utilizar WPF em Windows Forms e com isso usar todas as suas potencialidades. Muitos utilizadores queixam-se dos controlos disponíveis no Visual Studio e esta é uma oportunidade de criar os seus próprios controlos quase sem limites. Estes dois exemplos iram mostrar como incorporar um controlo WPF em Windows Forms e como fazer algumas alterações com o objectivo de melhorar visualmente os mesmos.
Para criar um controlo WPF é apenas necessário adicionar um novo item ao projecto (desde que esteja seleccionado a plataforma . NET Framework 3.0 ou superior) e seleccionar User Control (WPF)
Depois, para cada controlo, indicar o nome pretendido de acordo com os exemplos.
wpfPictureBox
Este controlo tem algumas personalizações com é o caso de:
- Sombra na PictureBox
- Possibilidade de alterar a opacidade da imagem
No editor de XAML utilizar o seguinte código:
<UserControl x:Class="wpfPictureBox"
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="300" Height="300">
<!-- Definição da imagem e da sombra –>
<Image Margin="10" x:Name="Image" Stretch="Uniform" Opacity="1">
<Image.BitmapEffect>
<DropShadowBitmapEffect Opacity="1" />
</Image.BitmapEffect>
</Image>
</UserControl>
Após compilar a aplicação ficará disponível na Toolbox o controlo wpfPictureBox. Arrastar para o Form, adicionar também uma TrackBar e utilizar o seguinte código para definir a imagem e alterar a opacidade da imagem:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' Definições da TrackBar
Me.TrackBar1.Maximum = 100
Me.TrackBar1.Minimum = 0
Me.TrackBar1.Value = 100
' Carrega uma imagem no nosso controlo
WpfPictureBox1.Image.Source = New Windows.Media.Imaging.BitmapImage(New Uri("c:\imagem.jpg"))
End Sub
' Quando se mexe na TrackBar diminui/aumenta a opacidade da imagem
Private Sub TrackBar1_Scroll(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TrackBar1.Scroll
WpfPictureBox1.Image.Opacity = Me.TrackBar1.Value / 100
End Sub
wpfComboBox
Este controlo tem algumas personalizações (algumas apenas para ilustração das potencialidades do WPF) com é o caso de:
- Sombra na ComboBox
- Botão dentro da lista para adicionar novos itens
- Efeito de fundo na caixa e lista
No editor de XAML utilizar o seguinte código:
<UserControl x:Class="wpfComboBox"
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
Width="200" Height="30">
<ComboBox x:Name="wpfCombo" Margin="5" Foreground="White" BorderBrush="White" MaxDropDownHeight="150">
<!-- Define o efeito da sombra –>
<ComboBox.BitmapEffect>
<DropShadowBitmapEffect ShadowDepth="1" Opacity="1" Color="DarkSeaGreen" />
</ComboBox.BitmapEffect>
<!-- Define o efeito do fundo –>
<ComboBox.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="DarkSeaGreen" Offset="0" />
<GradientStop Color="White" Offset="1" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</ComboBox.Background>
<ComboBox.Resources>
<Style TargetType="{x:Type ComboBoxItem}">
<!-- Define o efeito do fundo para os itens –>
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush>
<GradientStop Color="DarkSeaGreen" Offset="0"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<!-- Define a cor do texto dos items –>
<Setter Property="Foreground" Value="White" />
</Style>
</ComboBox.Resources>
<!-- Insere um botão para criar um novo item –>
<Button x:Name="btnCombo" Width="150" Background="White" Height="22" Foreground="DarkSeaGreen">
<TextBlock>Inserir novo item ... </TextBlock>
</Button>
</ComboBox>
</UserControl>
Após compilar a aplicação ficará disponível na Toolbox o controlo wpfComboBox. Arrastar para o Form e utilizar o seguinte código para o preencher e detectar que o botão foi pressionado:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' Insere alguns itens na wpfCombobox
For x As Byte = 0 To 20
WpfComboBox1.wpfCombo.Items.Add("Combobox Item " & x.ToString.PadLeft(2, "0"c))
Next
' Define uma acção para quando for pressionado o botão da wpfComboBox
AddHandler WpfComboBox1.btnCombo.Click, AddressOf btnComboBoxClick
End Sub
Sub btnComboBoxClick()
MessageBox.Show("Adicionar um novo item à wpfComboBox")
End Sub
São pequenos exemplos que mostram como utilizar controlos WPF numa aplicação WinForms. Com estes controlos consegue-se personalizar bastante a aplicação e melhorar o aspecto visual.
PS: Como sempre, qualquer dúvida, comentário ou correcção ao artigo é sempre bem vinda!
ComboBox editável em uma DataGridViewComboBoxColumn
A DataGridViewComboBoxColumn é uma coluna onde estão diversas DataGridViewComboBoxCell, ou seja, caixas de selecção que permitem seleccionar um item de uma lista de itens. Esses itens podem ser definidos de diversas formas e podem mesmo estar ligados a uma fonte de dados. No entanto, e através de uma inserção normal, não é possível editar a ComboBox.
Uma das formas de o fazer é utilizando o evento EditingControlShowing para alterar o tipo de ComboBox, de modo a permitir a edição. Esta opção não está disponível no IDE como propriedade e é possível apenas consegui-lo através de código.
Este pequeno exemplo mostra como o fazer, sendo diferente se a ComboBox estiver vinculada a uma fonte de dados. No entanto este exemplo mostra o processo a seguir.
Private dgvComboColumn As DataGridViewComboBoxColumn
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' Definições da ComboBoxColumn e insere alguns itens
dgvComboColumn = New DataGridViewComboBoxColumn
With dgvComboColumn
.Name = "ComboBoxColumn"
.HeaderText = "Seleccionar"
.Items.AddRange(New Object() {"Banana", "Morango", "Laranja"})
End With
' Adiciona a ComboBoxColumn à DataGridView
Me.DataGridView1.Columns.Add(dgvComboColumn)
End Sub
' No evento EditingControlShowing vai alterar o tipo de ComboBox
Private Sub DataGridView1_EditingControlShowing(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) Handles DataGridView1.EditingControlShowing
' Verifica se a coluna é a pretendida e define o novo tipo (DropDown)
If Me.DataGridView1.CurrentCell.ColumnIndex = dgvComboColumn.Index Then
Dim cb As ComboBox = DirectCast(e.Control, ComboBox)
cb.DropDownStyle = ComboBoxStyle.DropDown
' Adiciona um evento para verificar se é um novo item
AddHandler cb.Leave, AddressOf comboBoxLeave
End If
End Sub
' Quando o focus sai da ComboBox
Sub comboBoxLeave(ByVal sender As Object, ByVal e As System.EventArgs)
Dim cb As ComboBox = DirectCast(sender, ComboBox)
' Caso o item não esteja na lista
If Not dgvComboColumn.Items.Contains(cb.Text) Then
Dim msg As String = "Deseja inserir este novo item na lista ?"
Dim result As DialogResult
result = MessageBox.Show(msg, My.Application.Info.Title, MessageBoxButtons.YesNo, MessageBoxIcon.Question)
' Caso pretenda inserir o novo item, adiciona-o
If result = Windows.Forms.DialogResult.Yes Then
dgvComboColumn.Items.Add(cb.Text)
' Selecciona o novo item
Me.DataGridView1("ComboBoxColumn", DataGridView1.CurrentRow.Index).Value = cb.Text
End If
End If
End Sub
Comparar se duas imagens são iguais
Uma das formas de comparar se duas imagens são iguais é convertendo as imagens, utilizando o método Convert.ToBase64String(), para uma string. Este método converte um array de 8-bit inteiros para a sua representação com base em 64 dígitos.
É um método muito simples para algumas aplicações onde é necessário comparar imagens.
Atenção: não confundir com tamanho, dimensão, etc,
''' <summary>
''' Converte a imagem para base 64
''' </summary>
''' <param name="image">Imagem a converter</param>
''' <param name="format">Formato da imagem</param>
Public Function ImageToBase64String(ByVal image As Image, ByVal format As Imaging.ImageFormat) As String
Dim base64String As String = String.Empty
Using memory As New IO.MemoryStream()
image.Save(memory, format)
base64String = Convert.ToBase64String(memory.ToArray())
End Using
Return base64String
End Function
' Verifica se as imagens são iguais ou não
Private Sub btnTest_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnTest.Click
' Guarda as imagens em memória
Dim img1 As Image = Image.FromFile("c:\image1.jpg")
Dim img2 As Image = Image.FromFile("c:\image2.jpg")
' Converte as imagens para base 64
Dim base64String1 As String = ImageToBase64String(img1, Imaging.ImageFormat.Jpeg)
Dim base64String2 As String = ImageToBase64String(img2, Imaging.ImageFormat.Jpeg)
' Compara se as strings geração são iguais
If base64String1 = base64String2 Then
MessageBox.Show("As imagens são iguais")
Else
MessageBox.Show("As imagens são diferentes")
End If
End Sub
PS: Como sempre, qualquer dúvida, comentário ou correcção ao artigo é sempre bem vinda!