Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
C# / VB.NET - [VB.NET 2013] copia dati da un datagridview ed incollo su mail outlook
Forum - C# / VB.NET - [VB.NET 2013] copia dati da un datagridview ed incollo su mail outlook

Pagine: [ 1 2 3 ] Precedente | Prossimo
Avatar
robypiro (Normal User)
Newbie


Messaggi: 11
Iscritto: 09/02/2016

Segnala al moderatore
Postato alle 17:18
Martedì, 09/02/2016
salve a tutti,
gli utilizzatori di una piccola applicazione che ho svilupato necessitano di dover copiare alcune righe da un datagridview ed incollarle su di una mail (outlook). La copia dei dati avviene correttamente con il solito ctrl+c ma, così facendo, si copiano i dati perdendo la formattazione della griglia. In pratica mi servirebbe fare un copia/incolla in stile access, è possibile?

PM Quote
Avatar
Thejuster (Admin)
Guru^2


Messaggi: 2305
Iscritto: 04/05/2008

Segnala al moderatore
Postato alle 9:09
Mercoledì, 10/02/2016
Nella programmazione tutto e possibile.
Dipende pi dal tuo livello di preparazione.

Normalmente nella clipboard il formato data e quello che viene
Assegnato dall'utente.

Un semplice copia-incolla non sempre funziona.

Outlook di norma accetta il data in html.

Dovresti con una funzione generare codice html e con
I relativi dati della gridview esempio.

String b = "<b>" + gridview.Rows[0].Cell[0].value.ToString() + "</b>";
Clipboard.SetTex(b);

Prova in questo modo



https://mire.forumfree.it/ - Mire Engine
C# UI Designer
PM Quote
Avatar
robypiro (Normal User)
Newbie


Messaggi: 11
Iscritto: 09/02/2016

Segnala al moderatore
Postato alle 15:32
Mercoledì, 10/02/2016
Ho provato ad intercettare la pressione di ctrl+c e fare poi il codice html ma, quando vado ad incollare su outlook, mi incolla il testo comprensivo di tutti i tag html. Questo è il codice di esempio che sto provando prima i fare il ciclo per leggere le righe selezionate:

Codice sorgente - presumibilmente VB.NET

  1. Private Sub DataGridView1_KeyUp(sender As Object, e As KeyEventArgs) Handles DataGridView1.KeyUp
  2.         Dim a As String
  3.         If e.Modifiers = Keys.Control AndAlso e.KeyCode = Keys.C Then
  4.             a = "<HTML>"
  5.             a = a + "<TABLE>"
  6.             a = a + "<TR>"
  7.             a = a + "<TD>prova prova</TD>"
  8.             a = a + "</TR>"
  9.             a = a + "</TABLE></HTML>"
  10.             Clipboard.SetText(a)
  11.         End If
  12.     End Sub



Poi, tanto che ci siamo, questo codice per intercettare il ctrl+c sembra funzionare solo ogni tanto, non sempre

Ultima modifica effettuata da robypiro il 10/02/2016 alle 15:46
PM Quote
Avatar
GN (Member)
Guru


Messaggi: 772
Iscritto: 30/04/2011

Segnala al moderatore
Postato alle 17:18
Mercoledì, 10/02/2016
Non sono sicuro, ma probabilmente Outlook e altri programmi che usano il rendering engine di IE/Microsoft interpretano il contenuto della clipboard come HTML solo se glielo si "indica"; questa documentazione (non ho letto tutto) https://msdn.microsoft.com/en-us/library/aa767917(v=vs.85). ... spiega come mettere HTML nella clipboard. Probabilmente devi quindi aggiungere un header (come specificato in quella pagina) ed utilizzare la versione del metodo SetText che prende due argomenti (https://msdn.microsoft.com/it-it/library/ms597044(v=vs.110) ..., passando al secondo parametro il formato esatto, cioè TextDataFormat.Html (per ulteriori informazioni vedi https://msdn.microsoft.com/it-it/library/ms597044(v=vs.110) ....

Inoltre c'è una domanda simile alla tua qui http://stackoverflow.com/questions/13332377/how-to-set-htm ...

PM Quote
Avatar
robypiro (Normal User)
Newbie


Messaggi: 11
Iscritto: 09/02/2016

Segnala al moderatore
Postato alle 11:18
Giovedì, 11/02/2016
Grazie delle risposte! Ho provato a leggere i documenti indicati, ma ancora non ci sono. Facendo questo codice, seguendo le indicazioni dei documenti, non mi carica niente nella clipboard

Codice sorgente - presumibilmente VB.NET

  1. Private Sub DataGridView1_KeyUp(sender As Object, e As KeyEventArgs) Handles DataGridView1.KeyUp
  2.         Dim a As String
  3.         If e.Modifiers = Keys.Control AndAlso e.KeyCode = Keys.C Then
  4.             a = "Version:0.9 StartHTML:000125 EndHTML:000260 StartFragment:000209 EndFragment:000222 <!DOCTYPE>"
  5.             a = a + "<HTML>"
  6.             a = a + "<HEAD></HEAD>"
  7.             a = a + "<BODY>"
  8.             a = a + "<!-StartFragment->"
  9.             a = a + "<TABLE>"
  10.             a = a + "<TR>"
  11.             a = a + "<TD>prova prova</TD>"
  12.             a = a + "</TR>"
  13.             a = a + "</TABLE><!-EndFragment-></BODY></HTML>"
  14.             Dim DataObject = New DataObject()
  15.             DataObject.SetData(DataFormats.Html, a)
  16.             Clipboard.SetDataObject(DataObject)
  17.         End If
  18.     End Sub


PM Quote
Avatar
GN (Member)
Guru


Messaggi: 772
Iscritto: 30/04/2011

Segnala al moderatore
Postato alle 16:24
Giovedì, 11/02/2016
Dunque, mi sembra ci siano alcune cose che non vanno nel tuo codice (ovviamente potrei sbagliarmi):

-scrivere
Codice sorgente - presumibilmente Plain Text

  1. a = a + "<HTML>"
  2. a = a + "<HEAD></HEAD>"


e smili, NON inserisce un ritorno a capo tra <html> e <head>! Potrebbe non centrare con il problema, comunque visto che è scritto in quel modo mi sembrava giusto fartelo notare (magari poi lo sapevi già e l'hai scritto così per qualche altro motivo). Per inserire un ritorno a capo in una stringa, usa Environment.NewLine:
Codice sorgente - presumibilmente Plain Text

  1. a = "riga1" + Environment.NewLine + "riga2"



-probabilmente i ritorni a capo servono invece nell'header, o almeno così sembra dalla documentazione; penso dovresti quindi separare i vari campi con ritorni a capo.

-ti consiglio di assegnare sempre un tipo alle variabili, e di non usare nomi di variabile uguali a nomi di classi/tipi, fra l'altro mi sembra strano che il compilatore ti permetta di farlo, ma con
Codice sorgente - presumibilmente C# / VB.NET

  1. Dim DataObject = New DataObject()


stai creando una brutta ambiguità: adesso cos'è DataObject, una variabile o una tipo? Io scriverei piuttosto qualcosa come
Codice sorgente - presumibilmente C# / VB.NET

  1. Dim htmlDO As DataObject = New DataObject()



-nella risposta precedente dicevo
Testo quotato

utilizzare la versione del metodo SetText che prende due argomenti


che secondo la risposta su Stackoverflow funziona, ed è molto più semplice. Poi potrei sbagliarmi io, ma quello che hai scritto alle righe 14, 15 e 16 mi sembra un'inutile complicazione. Io intendevo
Codice sorgente - presumibilmente Plain Text

  1. Clipboard.SetText(a, TextDataFormat.Html)



-rimane poi da risolvere il problema degli indici: come indicato nella documentazione, devi indicare il numero di byte dall'inizio della clipboard (penso quindi tenendo conto anche dell'header) all'inizio e alla fine dell'html. Se ho tempo più tradi provo a farlo io e se riesco ti do ulteriori informazioni.

Ultima modifica effettuata da GN il 11/02/2016 alle 16:27
PM Quote
Avatar
robypiro (Normal User)
Newbie


Messaggi: 11
Iscritto: 09/02/2016

Segnala al moderatore
Postato alle 16:47
Giovedì, 11/02/2016
Ha fatto le modifiche che mi ha indicato, però non saprei come calcolare il numero dei byte anche perchè non so a priopri quante righe l'utente andrà a copiare. Adesso il codice è così e, ahi me, ancora non funziona (dopo aver fatto crtl+c, su outlook il crtl+v non da niente)

Codice sorgente - presumibilmente VB.NET

  1. Private Sub DataGridView1_KeyUp(sender As Object, e As KeyEventArgs) Handles DataGridView1.KeyUp
  2.         Dim a As String
  3.         If e.Modifiers = Keys.Control AndAlso e.KeyCode = Keys.C Then
  4.             a = "Version:0.9"
  5.             a = a + Environment.NewLine + "StartHTML:000125"
  6.             a = a + Environment.NewLine + "EndHTML:000260"
  7.             a = a + Environment.NewLine + "StartFragment:000209"
  8.             a = a + Environment.NewLine + "EndFragment:000222"
  9.             a = a + Environment.NewLine + "<!DOCTYPE>"
  10.             a = a + Environment.NewLine + "<HTML>"
  11.             a = a + Environment.NewLine + "<HEAD></HEAD>"
  12.             a = a + Environment.NewLine + "<BODY>"
  13.             a = a + Environment.NewLine + "<!-StartFragment->"
  14.             a = a + Environment.NewLine + "<TABLE>"
  15.             a = a + Environment.NewLine + "<TR>"
  16.             a = a + Environment.NewLine + "<TD>prova prova</TD>"
  17.             a = a + Environment.NewLine + "</TR>"
  18.             a = a + Environment.NewLine + "</TABLE>"
  19.             a = a + Environment.NewLine + "<!-EndFragment->"
  20.             a = a + Environment.NewLine + "</BODY>"
  21.             a = a + Environment.NewLine + "</HTML>"
  22.             Clipboard.SetText(a, TextDataFormat.Html)
  23.         End If
  24.     End Sub


PM Quote
Avatar
GN (Member)
Guru


Messaggi: 772
Iscritto: 30/04/2011

Segnala al moderatore
Postato alle 21:43
Giovedì, 11/02/2016
Ok, ho risolto.
Premetto che non so se sia il modo migliore di farlo, e che non era mio intento fornire il codice "pronto" ma spiegare come farlo, però ho dovuto fare un po' di prove e sono arrivato a questo frammento di codice funzionante. Ho cercato di commentare molto in modo da spiegare come funziona.

Prima di tutto serve una funzione che sostituisca solo la prima occorrenza in una stringa. Eccola (mettila nel tuo sorgente da qualche parte dove non crea problemi, magari nello stesso file fuori dal Sub che gestisce l'evento):
Codice sorgente - presumibilmente VB.NET

  1. Public Function replaceFirst(text As String, search As String, replace As String) As String
  2.                 Dim i As Integer = text.IndexOf(search) 'posizione del primo carattere della stringa da sostituire
  3.                 If i < 0 Then Return text 'se non viene trovata l'occorrenza, restituisce la stringa invariata
  4.                 Return text.Substring(0, i) + replace + text.Substring(i + search.Length) 'componiamo la stringa risultante concatenando la parte della stringa originale prima del frammento da sostituire, la stringa da sostituire, e la parte dopo
  5. End Function


Credit: mi sono leggermente ispirato (ok, non poi così leggermente :rotfl:, l'ho più che altro "tradotta") a questa http://stackoverflow.com/a/8809437

Poi, ecco qua la "soluzione" che ho implementato:
Codice sorgente - presumibilmente VB.NET

  1. 'Il contenuto formattato in HTML che vogliamo copiare nella clipboard:
  2. Dim tabella As String = "<table border='1'><tr><td><b>riga1</b></td></tr><tr><i>riga2</i></tr></title>"
  3. 'inizializzo la stringa da mettere nella clipboard con l'header, per ora senza settare gli indici. Al loro posto metto degli zeri, in modo da fissare una lunghezza per la stringa
  4. Dim a As String = "Version:0.9" + vbCrLf +"StartHTML:000000" + vbCrLf +"EndHTML:000000" + vbCrLf +"StartFragment:000000" + vbCrLf +"EndFragment:000000" + vbCrLf
  5. 'ora aggiungiamo alla stringa da copiare l'html necessario.
  6. 'ottengo la dimensione della stringa convertendo la stringa in un array di byte con la codifica UTF8 e leggendone la dimensione
  7. Dim headerSize As Integer = Text.Encoding.UTF8.GetBytes(a).Length
  8. a += tabella
  9. 'ottengo la dimensione della stringa convertendo la stringa in un array di byte con la codifica UTF8 e leggendone la dimensione
  10. Dim totalSize As Integer = Text.Encoding.UTF8.GetBytes(a).Length
  11. 'l'HTML inizia appena dopo l'header e finisce alla fine della clipboard,
  12. 'quindi abbiamo l'indice di inizio in headerSize e quello di fine in totalSize.
  13. 'A questo punto posso sostituire gli zeri con i valori trovati, facendo attenzione che questi siano di esattamente 6 cifre come i 6 zeri
  14. '(utilizzando padLeft sulla stringa la porto ad dimensione di 6 caratteri aggiungendo zeri a sinistra)
  15. Dim inizio As String = headerSize.ToString().padLeft(6, "0")
  16. Dim fine As String = totalSize.ToString().padLeft(6, "0")
  17. 'la prima occorrenza degli zeri (per StartHTML) la sostituisco con l'indice di inizio
  18. a = replaceFirst(a, "000000", inizio)
  19. 'la seconda (EndHTML) con l'indice di fine
  20. a = replaceFirst(a, "000000", fine)
  21. 'stessa cosa per StartFragment e EndFragment
  22. a = replaceFirst(a, "000000", inizio)
  23. a = replaceFirst(a, "000000", fine)
  24. Clipboard.SetText(a, TextDataFormat.Html)


La principale modifica che dovresti fare, ovviamente, è mettere al posto della stringa tabella i tuoi dati (come vedi nell'esempio ne ho messi alcuni a caso, giusto per provare la formattazione).
Come spiegato nei commenti il trucco sta nel mettere inizialmente degli zeri nell'header (ma in realtà porebbe essere qualsiasi altro carattere che in UTF8 ha una codifica in cui 1 char = 1 byte, come un'altra cifra o una lettera) per misurarne correttamente la lunghezza, e poi quando si conoscono i dati sostituirli al posto giusto.

Ho provato a farlo girare in una semplice applicazione console, poi ho incollato in Word e come previsto ho ottenuto la tabellina con la prima riga in grassetto e la seconda in corsivo. Immagino che su Outlook funzioni ugualmente (del resto a quanto ho capito questo formato per la clipboard è uno standard su Windows, inoltre immagino che i programmi Microsoft come quelli della suite Office gestiscano tutti il paste in HTML).

Una soluzione più elaborata e "seria", però in C# (da cui ho preso spunto), è spiegata qui http://theartofdev.com/2014/06/12/setting-htmltext-to-clip ....

Ultima modifica effettuata da GN il 11/02/2016 alle 21:47
PM Quote
Avatar
robypiro (Normal User)
Newbie


Messaggi: 11
Iscritto: 09/02/2016

Segnala al moderatore
Postato alle 11:54
Venerdì, 12/02/2016
Ti ringrazio tantissimo :hail: . Il tuo esempio funziona alla perfezione e direi che, senza il tuo aiuto, non ci sarei mai arrivato!
Purtroppo mi trovo ora davanti ad un altro problema: l'intercetto del crtl+c sopra il datagridview sembra funzionare solo ogni tanto o in modo strano... Mi spiego, se faccio questa prova:

Codice sorgente - presumibilmente VB.NET

  1. Private Sub DataGridView1_KeyDown(sender As Object, e As KeyEventArgs) Handles DataGridView1.KeyDown
  2.         If e.Modifiers = Keys.Control AndAlso e.KeyCode = Keys.C Then
  3.             MsgBox("CRTL+C")
  4.         End If
  5.     End Sub



Ogni volta che premo ctrl+c sopra il datagridview, mi appare, correttamente, il popup di avviso "CTRL+C". Ma se inserisco all'interno di quell'if il tuo codice di esempio e poi vado ad incollare su outlook, la maggior parte delle volte mi copia il contenuto della datagridview in maniera non formattata come se il codice non ci fosse, poi, qualche volta invece, copia la tabella di esempio. E' come se windows avesse una specie di precedenza sulla gestione della clipboard rispetto al codice del programma stesso.
Questo problema lo posso aggirare inserendo un pulsantino "COPIA" sopra il datagridview e poi faccio spingere quello agli utenti per copiare le righe, però questa cosa è abbastanza strana...

PM Quote
Pagine: [ 1 2 3 ] Precedente | Prossimo