Descrizione :
Un mio progetto con numerose idee sulla gestione avanzata di controlli Windows Forms.
+ Articolo :
In questo articolo mi sono divertito un po' a mettere insieme una tecnica sulla gestione di controlli a runtime in VB.NET.
Nella fattispecie parliamo di una Classe, la "PBox", che eredita da PictureBox, cercando di sfruttare, o almeno di dare un'indicazione a tutti quelli che vorranno provare, su come sfruttare l'enorme potenzialità di VB.NET, soprattutto se confrontato con il "fratellino" VB6, dal quale moltissimi ancora stentano a separarsi.
Lo scopo dell'articolo, che vuole essere soprattutto propositivo, e che quindi certamente risente di scelte personali e soggettive ( salterà all'occhio in questo caso, quella di aver fatto a meno dei DataBindings, BindingSource, ecc, e di aver gestito diversamente l'aggiornamento del DataTable... ) , è perciò quello di fornire qualche tecnica interessante sulla gestione in generale dei Controls a runtime. Il tutto inserito in un qualcosa a cui ho voluto dare uno scopo finale.
Di carne al fuoco ce n'è parecchia, perciò cercherò di essere il più stringato possibile.
Il Progetto consente tutte le seguenti operazioni a runtime su oggetti della Classe PBox :
--> Aggiungere nuova PBox in 3 modi :
PBox vuota / PBox da file / PBox con Drag & Drop.
--> Eliminare PBox.
--> Clonare PBox da esistente.
--> Spostare e ridimensionare PBox con il Mouse :
Il Container è uno ScrollableControl ( in questo caso un Panel ), e le operazioni di spostamento possono portare a gestire un'area delle dimensioni ben superiori a quella della sola Form visibile.
--> Aggiungere 2 Immagini distinte per ogni PBox, una di sfondo e una principale.
--> Modificare ogni modalità di disegno disponibile per ognuna delle 2 Immagini :
5 Layout diversi per lo sfondo e 5 SizeMode diversi per la principale.
--> Modificare l'ordine di sovrapposizione "ZOrder" con 4 funzioni :
Porta Avanti / Indietro / Primo Piano / Dietro a Tutti.
--> Modificare il colore di sfondo.
--> Salvataggio degli oggetti PBox in formato XML.
--> Caricamento degli oggetti PBox.
--> Salvataggio dell'intero container in formato immagine Bitmap :
Il salvataggio non avviene con un banale capture screen, bensì l'intera area dello ScrollableControl viene trasferita su file Bitmap, comprendendo anche le aree soggette a Scroll e al momento non visibili.
Il tutto viene gestito via Mouse e con una speciale "Form Menu", richiamata con un Click Destro sulla PBox, che non è necessario aprire e chiudere ogni volta per ogni PBox che si vuole modificare, ma che una volta aperta, sta in primo piano sulla Form dell'applicazione e si ancora automaticamente alla PBox selezionata.
Per ragioni di semplicità, e visto anche che le funzioni che volevo implementare erano ben altre, ho volutamente scelto di non gestire controlli inseriti a design. Dal momento che tutta la situazione si può salvare, credo sia un aspetto di importanza minima. Ovviamente la gestione degli errori è quella essenziale. Ho evitato di inserire Try Catch in ogni situazione passibile di errore. In ogni caso l'applicazione funziona perfettamente.
Dato che ho deciso di allegare direttamente i sorgenti, evito la lunga descrizione dei controlli con nomi e proprietà da impostare a design.
Come spesso accade, un'immagine vale più di mille parole :
Il DataGridView in alto è solo a scopo descrittivo e mostra come ogni operazione mappata sugli oggetti PBox viene registrata in una Classe apposita, che eredita da DataTable, e che si occupa di tutte le operazioni esterne, aggiunta, eliminazione, clonazione, salvataggio e caricamento XML.
Al di sotto dei pulsanti c'è il Panel, ossia il contenitore in cui inserire e gestire i Controls PBox.
L'immagine mostra 4 PBox con altrettante immagini PNG trasparenti, due con immagine di sfondo, e due senza. Questo per dare un'idea di come l'oggetto "capisca" che tipo di immagine contiene e la mostri correttamente. Per le GIF è ancora meglio, in quanto, se una .gif inserita come immagine principale, è animata, allora la PBox mostrerà anche l'animazione.
FILE e CLASSI :
1. DTPBoxes.vb :
La classe che eredita da DataTable e si occupa della memorizzazione e della gestione degli Oggetti Pbox.
'***********************************************************************************
'************** Gestione Avanzata Controlli PBox ***** MARCOGG 2011 ****************
'***********************************************************************************
Public Class DTPBoxes
Inherits DataTable
Private m_parentcontrol As Control
Private m_iddisp As Integer
Private m_cloneoffsetxy As Integer = 20
Private m_propertyname As String
Private m_propertyvalue As String
Public ReadOnly Property IdDisp() As Integer
Get
If Me.Rows.Count = 0 Then Return 1
m_iddisp = 0
Do
m_iddisp += 1
If Me.Rows.Find(m_iddisp) Is Nothing Then Return m_iddisp
Loop
End Get
End Property
Public Sub New(ByVal parentControl As Control)
m_parentcontrol = parentControl
Me.TableName = "PBox"
'PK
Me.Columns.Add("ID") '0
Me.PrimaryKey = New DataColumn() {Me.Columns("ID")}
'Campi
With Me.Columns
.Add("ZOrder", System.Type.GetType("System.Int32")) '1
'-----------------------------
.Add("BackColor")
.Add("FileImmagineSfondo")
.Add("BackgroundImageLayout")
.Add("FileImmagine")
.Add("SizeMode")
.Add("Left")
.Add("Top")
.Add("RealLeft")
.Add("RealTop")
.Add("Width")
.Add("Height")
.Add("MinimumSize")
End With
End Sub
Public Sub Aggiorna(ByVal pbx As PBox)
Dim pbxRow As DataRow = Me.Rows.Find(pbx.ID)
If pbxRow IsNot Nothing Then
For i As Integer = 1 To Me.Columns.Count - 1
m_propertyname = Me.Columns(i).ColumnName
pbxRow.Item(m_propertyname) = pbx.GetPropertyValue(m_propertyname)
Next
End If
End Sub
Public Sub AggiornaTutti()
For Each C As Control In m_parentcontrol.Controls
If TypeOf (C) Is PBox Then Me.Aggiorna(DirectCast(C, PBox))
Next
End Sub
Public Sub Aggiungi(ByVal pbx As PBox)
With pbx
.ID = Me.IdDisp
m_parentcontrol.Controls.Add(pbx)
.BringToFront()
Me.Rows.Add(New Object() {.ID})
End With
Me.AggiornaTutti()
End Sub
Public Sub Clona(ByVal pbx As PBox)
Dim newPbx As New PBox
Me.Aggiungi(newPbx)
newPbx.AggiornaDTPEnabled = False
For i As Integer = 2 To Me.Columns.Count - 1
m_propertyname = Me.Columns(i).ColumnName
m_propertyvalue = pbx.GetPropertyValue(m_propertyname)
newPbx.SetPropertyValue(m_propertyname, m_propertyvalue)
Next
newPbx.Left += m_cloneoffsetxy
newPbx.Top += m_cloneoffsetxy
newPbx.AggiornaDTPEnabled = True
End Sub
Public Sub Rimuovi(ByVal pbx As PBox)
pbx.AggiornaDTPEnabled = False
Me.Rows.Remove(Me.Rows.Find(pbx.ID))
m_parentcontrol.Controls.Remove(pbx)
Me.AggiornaTutti()
End Sub
Public Sub RimuoviTutti()
For i As Integer = m_parentcontrol.Controls.Count - 1 To 0 Step -1
If TypeOf (m_parentcontrol.Controls(i)) Is PBox Then Me.Rimuovi(m_parentcontrol.Controls(i))
Next
End Sub
Public Sub Salva()
Me.DefaultView.Sort = "ZOrder DESC"
Me.DefaultView.ToTable.WriteXml(percorso & nomeFileSalvataggio)
End Sub
Private Sub CaricaXml(ByVal nomeFileXml As String)
Me.RimuoviTutti()
Me.Clear()
Me.ReadXml(nomeFileXml)
Dim pbx As PBox
For row As Integer = 0 To Me.Rows.Count - 1
pbx = New PBox
pbx.AggiornaDTPEnabled = False
m_parentcontrol.Controls.Add(pbx)
For col As Integer = 0 To Me.Columns.Count - 1
m_propertyname = Me.Columns(col).ColumnName
m_propertyvalue = Me.Rows(row).Item(m_propertyname)
pbx.SetPropertyValue(m_propertyname, m_propertyvalue)
Next
pbx.PrimoPiano()
pbx.Left = pbx.RealLeft
pbx.Top = pbx.RealTop
pbx.AggiornaDTPEnabled = True
Next
AggiornaTutti()
End Sub
Public Sub Carica()
Try
CaricaXml(percorso & nomeFileSalvataggio)
Catch ex As Exception
End Try
End Sub
Public Sub SelezionaSuDgv(ByVal pbx As PBox)
With DirectCast(m_parentcontrol.Parent, FormMain).dgvtest
For Each r As DataGridViewRow In .Rows
If r.Cells("ID").Value = pbx.ID Then r.Selected = True
Next
End With
End Sub
End Class
2. FormMain.vb :
La Form di avvio.
L'apparente complessità della routine sotto il Button cmd_salvasnapshot su FormMain, è dovuta al workaround di un bug che affligge, a quanto pare, il Metodo DrawToBitmap(). Perciò non è imputabile al mio codice. Effettivamente, DrawToBitmap sballa l'ordine degli ZOrders ( Primo Piano, piani intermedi, Ultimo Piano... ). L'ordine dei piani delle PBox nel PNL viene invertito, nell'immagine bitmap risultante. Il problema perciò viene qui risolto con un workaround che inverte temporaneamente gli ZOrder delle PBox, per poi riportarli ai valori originari.
Public Class FormMain
Private Sub FormMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
With PNL
.AllowDrop = True
.AutoScroll = True
.Controls.Clear()
End With
DTP = New DTPBoxes(PNL)
With dgvtest
.MultiSelect = False
.SelectionMode = DataGridViewSelectionMode.FullRowSelect
.DataSource = DTP
End With
End Sub
Private Sub PNL_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles PNL.DragDrop
Dim fn As String = CType(e.Data.GetData(DataFormats.FileDrop), Array).GetValue(0).ToString
Try
Dim newPbx As New PBox
newPbx.FileImmagine = fn
DTP.Aggiungi(newPbx)
Catch ex As Exception
MessageBox.Show("File non supportato.", "Operazione Annullata", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
End Try
End Sub
Private Sub PNL_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles PNL.DragEnter
If (e.Data.GetDataPresent(DataFormats.FileDrop)) Then e.Effect = DragDropEffects.Copy
End Sub
Private Sub cmd_aggiungivuota_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmd_aggiungivuota.Click
DTP.Aggiungi(New PBox)
End Sub
Private Sub cmd_carica_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmd_carica.Click
DTP.Carica()
End Sub
Private Sub cmd_salva_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmd_salva.Click
DTP.Salva()
End Sub
Private Sub cmd_aggiungifile_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmd_aggiungifile.Click
Dim fn As String = GetFileImmagine()
If Not fn = String.Empty Then
Dim newPbx As New PBox
newPbx.FileImmagine = fn
DTP.Aggiungi(newPbx)
End If
End Sub
Private Sub cmd_salvasnapshot_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmd_salvasnapshot.Click
'-----------------------------------------
'Inversione degli ZOrder per Bug ZOrder :
Dim ids As New List(Of Integer)
Dim zorders As New List(Of Integer)
For Each pbx As PBox In PNL.Controls
ids.Add(pbx.ID)
zorders.Add(pbx.ZOrder)
Next
zorders.Reverse()
For i As Integer = 0 To ids.Count - 1
For Each pbx As PBox In PNL.Controls
If pbx.ID = ids(i) Then pbx.ZOrder = zorders(i)
Next
Next
'-----------------------------------------
PNL.AutoScrollPosition = New Point(0, 0)
My.Application.DoEvents()
Dim pnlW As Integer = PNL.Width
Dim pnlH As Integer = PNL.Height
Dim W As Integer
Dim H As Integer
For Each C As Control In PNL.Controls
If C.Right > W Then W = C.Right
If C.Bottom > H Then H = C.Bottom
Next
Try
W += SystemInformation.VerticalScrollBarWidth
H += SystemInformation.HorizontalScrollBarHeight
PNL.Width = W
PNL.Height = H
Using bmp As New Bitmap(W, H)
PNL.DrawToBitmap(bmp, New Rectangle(Point.Empty, bmp.Size))
bmp.Save(percorso & nomeFileSnapShot, Imaging.ImageFormat.Bmp)
End Using
Catch ex As Exception
MessageBox.Show("Impossibile creare l'immagine.", "Errore", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
Finally
PNL.Width = pnlW
PNL.Height = pnlH
End Try
'-----------------------------------------
'Ripristino Zorders per Bug Zorder
zorders.Reverse()
For i As Integer = 0 To ids.Count - 1
For Each pbx As PBox In PNL.Controls
If pbx.ID = ids(i) Then pbx.ZOrder = zorders(i)
Next
Next
'-----------------------------------------
MessageBox.Show("File SnapShot Bitmap creato.", "OK", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
End Class
3. FormMenu.vb :
Form per il Menu "Mobile".
Public Class FormMenu Private m_pbx As PBox Public Property PBX() As PBox Get Return m_pbx End Get Set(ByVal value As PBox) m_pbx = value Me.Text = m_pbx.ID 'Valore Combo per BackgroundImageLayout di m_pbx cmb_backgroundimagelayout.SelectedItem = [Enum].Format(GetType(ImageLayout), m_pbx.BackgroundImageLayout, "F") 'Valore Combo per SizeMode di m_pbx cmb_sizemode.SelectedItem = [Enum].Format(GetType(PictureBoxSizeMode), m_pbx.SizeMode, "F") 'Label BackColor lbl_backcolor.BackColor = m_pbx.BackColor Riposiziona() End Set End Property Private Sub FormMenu_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'Proprietà Me.ShowInTaskbar = False lbl_backcolor.Cursor = Cursors.Hand 'Combo per BackgroundImageLayout With cmb_backgroundimagelayout .Items.AddRange([Enum].GetNames(GetType(ImageLayout))) .DropDownStyle = ComboBoxStyle.DropDownList End With 'Combo per SizeMode With cmb_sizemode .Items.AddRange([Enum].GetNames(GetType(PictureBoxSizeMode))) .DropDownStyle = ComboBoxStyle.DropDownList End With End Sub Private Sub Riposiziona() Me.Visible = False Dim scrw As Integer = Screen.PrimaryScreen.Bounds.Width Dim scrh As Integer = Screen.PrimaryScreen.Bounds.Height Me.Left = m_pbx.PointToScreen(New Point(0, 0)).X + m_pbx.Width Me.Top = m_pbx.PointToScreen(New Point(0, 0)).Y If Me.Right > scrw Then Me.Left = m_pbx.PointToScreen(New Point(0, 0)).X - Me.Width If Me.Bottom > scrh Then Me.Top = m_pbx.PointToScreen(New Point(0, 0)).Y - Me.Height If Me.Left < 0 Then Me.Left = m_pbx.PointToScreen(New Point(0, 0)).X + m_pbx.Width If Me.Top < 0 Then Me.Top = 0 Me.Visible = True End Sub Private Sub FormMenu_MouseClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseClick If e.Button = Windows.Forms.MouseButtons.Right Then Me.Close() End Sub Private Sub cmd_elimina_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmd_elimina.Click DTP.Rimuovi(m_pbx) Me.Close() End Sub Private Sub cmd_clona_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmd_clona.Click DTP.Clona(m_pbx) End Sub Private Sub lbl_backcolor_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lbl_backcolor.Click Dim CD As New ColorDialog If CD.ShowDialog() = DialogResult.OK Then lbl_backcolor.BackColor = CD.Color m_pbx.BackColor = CD.Color End If End Sub Private Sub cmd_immaginesfondo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmd_immaginesfondo.Click Dim fn As String = GetFileImmagine() If Not fn = String.Empty Then m_pbx.FileImmagineSfondo = fn End Sub Private Sub cmd_immagine_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmd_immagine.Click Dim fn As String = GetFileImmagine() If Not fn = String.Empty Then m_pbx.FileImmagine = fn End Sub Private Sub cmb_backgroundimagelayout_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmb_backgroundimagelayout.SelectedIndexChanged Dim strSel As String = DirectCast(cmb_backgroundimagelayout.SelectedItem, String) m_pbx.BackgroundImageLayout = DirectCast([Enum].Parse(GetType(ImageLayout), strSel), ImageLayout) End Sub Private Sub cmb_sizemode_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmb_sizemode.SelectedIndexChanged Dim strSel As String = DirectCast(cmb_sizemode.SelectedItem, String) m_pbx.SizeMode = DirectCast([Enum].Parse(GetType(PictureBoxSizeMode), strSel), PictureBoxSizeMode) End Sub Private Sub cmd_primopiano_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmd_primopiano.Click m_pbx.PrimoPiano() End Sub Private Sub cmd_portaavanti_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmd_portaavanti.Click m_pbx.PortaAvanti() End Sub Private Sub cmd_dietrotutti_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmd_dietrotutti.Click m_pbx.DietroTutti() End Sub Private Sub cmd_portaindietro_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmd_portaindietro.Click m_pbx.PortaIndietro() End Sub End Class
4. ModuloPublics.vb :
Module ModuloPublics Public DTP As DTPBoxes Public percorso As String = Application.StartupPath & "\" Public nomeFileSalvataggio As String = "SalvataggioPBoxes.xml" Public nomeFileSnapShot As String = "SnapShot_PBoxes.bmp" Public Function GetFileImmagine() As String Dim fn As String = String.Empty Using OFD As New OpenFileDialog OFD.Title = "Selezionare File Immagine" OFD.Filter = "Immagini Supportate (*.bmp,*.jpg,*.jpeg,*.gif,*.png)" & _ "|*.bmp;*.jpg;*.jpeg;*.gif;*.png" OFD.FilterIndex = 1 OFD.InitialDirectory = My.Computer.FileSystem.SpecialDirectories.MyPictures If OFD.ShowDialog = Windows.Forms.DialogResult.OK Then fn = OFD.FileName End Using Return fn End Function Public Function GetImmagine(ByVal nomeFile As String) As Image Dim MS As New IO.MemoryStream(IO.File.ReadAllBytes(nomeFile)) Return Image.FromStream(MS) End Function End Module
5. PBox.vb :
In particolare vorrei far notare i due Metodi Reflection GetPropertyValue e SetPropertyValue, con cui è possibile leggere e impostare proprietà attraverso le relative definizioni in formato Stringa. Questo rende ancora più facile l'eventuale aggiunta di altre proprietà da mappare e gestire, e la conseguente serializzazione su file XML.
'***********************************************************************************
'************** Gestione Avanzata Controlli PBox ***** MARCOGG 2011 ****************
'***********************************************************************************
Public Class PBox
Inherits PictureBox
Private m_id As Integer 'ID univoco in DTI per salvataggio / caricamento
Private m_realleft As Integer 'Left effettivo in caso di Scroll orizzontale
Private m_realtop As Integer 'Top effettivo in caso di Scroll verticale
Private m_aggiornadtpenabled As Boolean = True 'Switch abilita/disabilita aggiornamento row DTI
Private m_tiposelezione As TipiSelezione = TipiSelezione.NS
Private m_resizewidthheight As Integer = 10 'Altezza/Larghezza Rect Resize
Private m_rectmovexy As Rectangle 'Rect per Move XY
Private m_rectresizewe As Rectangle 'Rect per Resize WE
Private m_rectresizens As Rectangle 'Rect per Resize NS
Private m_rectresizenwse As Rectangle 'Rect per Resize NWSE
Private m_openmenu As Boolean 'Check per Menu Opzioni
Private m_selx As Integer
Private m_sely As Integer
Private m_fileimmaginesfondo As String = String.Empty
Private m_fileimmagine As String = String.Empty
Public Property ID() As Integer
Get
Return m_id
End Get
Set(ByVal value As Integer)
m_id = value
End Set
End Property
Public Property ZOrder() As Integer
Get
If Me.Parent IsNot Nothing Then
Return Me.Parent.Controls.GetChildIndex(Me)
Else
Return 0
End If
End Get
Set(ByVal value As Integer)
If Me.Parent IsNot Nothing Then
Me.Parent.Controls.SetChildIndex(Me, value)
Me.AggiornaTuttiDTP()
End If
End Set
End Property
Public Property RealLeft() As Integer
Get
Return m_realleft
End Get
Set(ByVal value As Integer)
m_realleft = value
End Set
End Property
Public Property RealTop() As Integer
Get
Return m_realtop
End Get
Set(ByVal value As Integer)
m_realtop = value
End Set
End Property
Public Property AggiornaDTPEnabled() As Boolean
Get
Return m_aggiornadtpenabled
End Get
Set(ByVal value As Boolean)
m_aggiornadtpenabled = value
End Set
End Property
Public Property TipoSelezione() As TipiSelezione
Get
Return m_tiposelezione
End Get
Set(ByVal value As TipiSelezione)
m_tiposelezione = value
Select Case m_tiposelezione
Case TipiSelezione.MoveXY
Cursor = Cursors.SizeAll
Case TipiSelezione.ResizeWE
Cursor = Cursors.SizeWE
Case TipiSelezione.ResizeNS
Cursor = Cursors.SizeNS
Case TipiSelezione.ResizeNWSE
Cursor = Cursors.SizeNWSE
Case Else
Cursor = Cursors.Default
End Select
End Set
End Property
Public Property FileImmagineSfondo() As String
Get
Return m_fileimmaginesfondo
End Get
Set(ByVal value As String)
m_fileimmaginesfondo = value
If Not m_fileimmaginesfondo = String.Empty Then
Me.BackgroundImage = GetImmagine(m_fileimmaginesfondo)
AggiornaMeDTP()
End If
End Set
End Property
Public Property FileImmagine() As String
Get
Return m_fileimmagine
End Get
Set(ByVal value As String)
m_fileimmagine = value
If Not m_fileimmagine = String.Empty Then
Dim sizeTemp As Size = Me.Size
Me.Image = GetImmagine(m_fileimmagine)
Me.Size = sizeTemp
AggiornaMeDTP()
End If
End Set
End Property
#Region "Costruttore"
Public Sub New()
Me.BackColor = Color.White
Me.MinimumSize = New Size(m_resizewidthheight * 2, m_resizewidthheight * 2)
Me.BackgroundImageLayout = ImageLayout.None
m_rectmovexy = New Rectangle(0, 0, Me.Width - m_resizewidthheight, Me.Height - m_resizewidthheight)
m_rectresizewe = New Rectangle(Me.Width - m_resizewidthheight, 0, m_resizewidthheight, Me.Height - m_resizewidthheight)
m_rectresizens = New Rectangle(0, Me.Height - m_resizewidthheight, Me.Width - m_resizewidthheight, m_resizewidthheight)
m_rectresizenwse = New Rectangle(Me.Width - m_resizewidthheight, Me.Height - m_resizewidthheight, m_resizewidthheight, m_resizewidthheight)
End Sub
#End Region
#Region "Metodi"
'Metodo Reflection GetPropertyValue : lettura valore proprietà
Public Function GetPropertyValue(ByVal propertyName As String) As String
Dim propertyValue As Object
Dim PI As System.Reflection.PropertyInfo
PI = Me.GetType.GetProperty(propertyName)
propertyValue = PI.GetValue(Me, Nothing)
With PI.PropertyType
If .IsEnum Then propertyValue = Convert.ToInt32(propertyValue)
If .Name = "Color" Then propertyValue = ColorTranslator.ToWin32(Me.BackColor)
If .Name = "Size" Then propertyValue = CType(propertyValue, Size).Width & "|" & CType(propertyValue, Size).Height
End With
If propertyValue IsNot Nothing Then
Return propertyValue.ToString
Else
Return String.Empty
End If
End Function
'Metodo Reflection SetPropertyValue : assegnazione valore proprietà
Public Sub SetPropertyValue(ByVal propertyName As String, ByVal propertyValue As Object)
Dim PI As System.Reflection.PropertyInfo
PI = Me.GetType.GetProperty(propertyName)
If Not PI.CanWrite Then Exit Sub
With PI.PropertyType
If .IsEnum Then propertyValue = Convert.ToInt32(propertyValue)
If .Name = "Int32" Then propertyValue = Convert.ToInt32(propertyValue)
If .Name = "Color" Then propertyValue = ColorTranslator.FromWin32(propertyValue)
If .Name = "Size" Then propertyValue = New Size(propertyValue.ToString.Split("|")(0), _
propertyValue.ToString.Split("|")(1))
End With
PI.SetValue(Me, propertyValue, Nothing)
End Sub
Private Sub AggiornaMeDTP()
If DTP IsNot Nothing And Me.AggiornaDTPEnabled = True Then DTP.Aggiorna(Me)
End Sub
Private Sub AggiornaTuttiDTP()
If DTP IsNot Nothing And Me.AggiornaDTPEnabled = True Then DTP.AggiornaTutti()
End Sub
Public Sub PortaAvanti()
Me.ZOrder -= 1
End Sub
Public Sub PortaIndietro()
Me.ZOrder += 1
End Sub
Public Sub PrimoPiano()
Me.BringToFront()
Me.AggiornaTuttiDTP()
End Sub
Public Sub DietroTutti()
Me.SendToBack()
Me.AggiornaTuttiDTP()
End Sub
#End Region
#Region "Eventi"
Protected Overrides Sub OnResize(ByVal e As System.EventArgs)
'Aggiorna posizione e dimensione dei Rect di selezione
m_rectmovexy.Width = Me.Width - m_resizewidthheight
m_rectmovexy.Height = Me.Height - m_resizewidthheight
m_rectresizewe.X = Me.Width - m_resizewidthheight
m_rectresizewe.Height = Me.Height - m_resizewidthheight
m_rectresizens.Y = Me.Height - m_resizewidthheight
m_rectresizens.Width = Me.Width - m_resizewidthheight
m_rectresizenwse.X = Me.Width - m_resizewidthheight
m_rectresizenwse.Y = Me.Height - m_resizewidthheight
Me.AggiornaMeDTP()
Me.Refresh()
End Sub
Protected Overrides Sub OnLocationChanged(ByVal e As System.EventArgs)
Me.RealLeft = Me.Left - DirectCast(Me.Parent, ScrollableControl).AutoScrollPosition.X
Me.RealTop = Me.Top - DirectCast(Me.Parent, ScrollableControl).AutoScrollPosition.Y
Me.AggiornaMeDTP()
End Sub
Protected Overrides Sub OnBackColorChanged(ByVal e As System.EventArgs)
MyBase.OnBackColorChanged(e)
Me.AggiornaMeDTP()
End Sub
Protected Overrides Sub OnMouseClick(ByVal e As System.Windows.Forms.MouseEventArgs)
m_openmenu = False
For Each F As Form In My.Application.OpenForms
If TypeOf (F) Is FormMenu Then
m_openmenu = True
DirectCast(F, FormMenu).PBX = Me
Exit For
End If
Next
If e.Button = Windows.Forms.MouseButtons.Left Then
If DTP IsNot Nothing Then DTP.SelezionaSuDgv(Me)
End If
If e.Button = Windows.Forms.MouseButtons.Right Then
If m_openmenu = False Then
Dim FM As New FormMenu
FM.Show()
FM.PBX = Me
End If
End If
End Sub
Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs)
m_selx = e.X
m_sely = e.Y
If m_rectmovexy.Contains(m_selx, m_sely) Then Me.TipoSelezione = TipiSelezione.MoveXY
If m_rectresizewe.Contains(m_selx, m_sely) Then Me.TipoSelezione = TipiSelezione.ResizeWE
If m_rectresizens.Contains(m_selx, m_sely) Then Me.TipoSelezione = TipiSelezione.ResizeNS
If m_rectresizenwse.Contains(m_selx, m_sely) Then Me.TipoSelezione = TipiSelezione.ResizeNWSE
End Sub
Protected Overrides Sub OnMouseUp(ByVal e As System.Windows.Forms.MouseEventArgs)
Me.TipoSelezione = TipiSelezione.NS
End Sub
Protected Overrides Sub OnMouseMove(ByVal e As System.Windows.Forms.MouseEventArgs)
'MouseMove senza selezione
If Me.TipoSelezione = TipiSelezione.NS Then
If m_rectmovexy.Contains(e.X, e.Y) Then Cursor = Cursors.SizeAll
If m_rectresizewe.Contains(e.X, e.Y) Then Cursor = Cursors.SizeWE
If m_rectresizens.Contains(e.X, e.Y) Then Cursor = Cursors.SizeNS
If m_rectresizenwse.Contains(e.X, e.Y) Then Cursor = Cursors.SizeNWSE
End If
'MouseMove con selezione
If Me.TipoSelezione = TipiSelezione.MoveXY Then
Me.Left -= (m_selx - e.X)
Me.Top -= (m_sely - e.Y)
End If
If Me.TipoSelezione = TipiSelezione.ResizeWE Then
Me.Width += e.X - m_selx
m_selx = e.X
End If
If Me.TipoSelezione = TipiSelezione.ResizeNS Then
Me.Height += e.Y - m_sely
m_sely = e.Y
End If
If Me.TipoSelezione = TipiSelezione.ResizeNWSE Then
Me.Width += e.X - m_selx
Me.Height += e.Y - m_sely
m_selx = e.X
m_sely = e.Y
End If
End Sub
#End Region
End Class
6. TipiSelezione.vb :
Public Enum TipiSelezione NS = 0 MoveXY = 1 ResizeWE = 2 ResizeNS = 3 ResizeNWSE = 4 End Enum
Più che un singolo How-To, lo considero un insieme di tanti spunti, come ad esempio :
--> dotare una Classe di Metodi di accesso generico con la Reflection
--> popolare una ComboBox ( quelle su Form Menu ) direttamente con una Enum e farsi restituire il valore corrispondente
--> salvare l'intero contenuto di un Panel in una bitmap, comprese le aree non visibili
--> una parziale serializzazione dei Controls Forms, ecc, ecc...
+ Fine Articolo.



19:11
MarcoGG




Posted in:
1 commenti:
Inѕpirіng queѕt thеre.
What occurred after? Thanks!
Here is my wеbsite - Chios studios
Posta un commento