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.
1 commenti:
Inѕpirіng queѕt thеre.
What occurred after? Thanks!
Here is my wеbsite - Chios studios
Posta un commento