Storing Drag and drop items
Hello All.
I have a "Consultation" form in my VB.NET application. It is meant to catch a history of consultation with a client regarding a project application that they made. When a client files an issue with the company they may include emails, excel documents, pdf's and even (in the future) items for systems not yet written, and so forth.
The consultation system goes like this:
A Customer/client is a member of an organisation.
The client makes the application for funding on behalf of the organisation.
If there are any issues like, for example, the application is not filled correctly or completely, or the payments for funding fell down a black hole, or if they just need to get something off their chest related to the project application, then the system should be able to record that an issue was raised.
The "Consultation" Table contains the contact ID (The contact table contains the organisation ID), and other general data. Any consultation could in theory continue for some time and have many "events" attributed to it. Each of these events may be emails containing word documents,pdf's,excel documents or whatever. Therefore a consultation can have one or many consultation events.
Here is the question (and related sub-questions): How can I store the email and any attachments for any particular event by allowing the user to drag-drop an email into the system. What type of control could I use to allow the user to drag-drop an item like this.
I thought about storing each item added in a record in another table called consultationeventobjects which would simply reference the consultationevent item and have a field of type BLOB which would be the actual item (Email, word document ...)
My other issue is how to open the item if the user clicks on, say a email in this control.
I dont want a reference to the items dragged in case the source items are removed or moved, causing a broken link.
I hope someone has some good ideas.
I must also add that I am proposing using a "panel" control. Not quite sure how to display the items in the panel, but I have written some dragdrop code before (Eg. Dragging ListViewItems into a richtextbox) so I do understand the dragdrop mechanism as well.
Cheers,
NL.
[2286 byte] By [
NLARGE] at [2008-1-13]
You'll have to clear some things up here first. In what context is the email that is to be dropped? Is it some type of struct,class, etc., or is it being brought in from say a file list as a string or what? If your case is the later, you could just easily store the path of the email, and display it however you wanted. For example, store the path in item data or, for multiple emails, maybe an array or collection. Then you can handle the file the way your app normally does. You can do the reverse in the case of a user wanting to view the email. Take the full path and shell it out. I can't be sure of this answer though because I know nothing of your application. For the panel, you could probably draw an icon on the panel with GDI which is very easy and add a linked label or something else of your choice. Its also not too difficult to make this list collapseable also using GDI to keep things looking nice and organized. Just a few suggestions.
Hi Joe
Thanks for your reply. The email being dropped would be a Microsoft Outlook message, most likely with attachments. I have decided that a listview would be the best option in terms of GUI. The user would select the email in Outlook and drag the item onto the listview. The listview would then insert a description of the item, but the actual drag and drop event would store the item as a BLOB. When the user clicks on the item in the listview then the email (with attachments) would be opened.
An idea of the column headings for the listbox would be:
Date (When the file was drag-dropped)
Item Type (Eg. Word Document, Excel Document, Mail Message)
Item Name (Filename)
Additional Notes (Freetext)
I need the same if the item is (for example) an Excel Document. The user would drag it from explorer and a description would appear in the list (Along with the date and time that the item was dragged. If the user double clicks on the item in the listview then it will start up Excel and open the document.
Same for word documents, text documents etc.
In my perceived design (code) I would assume it possible to have a region in my Globals module called "DragDropObjects" which contains the functions to do the following:
(In the case of a file Eg. Word, Excel, Powerpoint, Text)
Save (Following a drag-drop): The file is loaded into a byte array and inserted into a new entry in the database (Consultationeventobject) as a blob.
Load (The user double clicks an item on the listview): The blob is extracted from the database, the file is recreated (preferably in memory rather then in a temp file, but if that is not possible then a temp file will have to do. The related application is used to open the object.
(In the case of a Mail Message)
Save (Following a drag-drop): The message (with attachments, if any) is loaded into a byte array and inserted into a new entry in the database (Consultationeventobject) as a blob.
Load (The user double clicks an item on the listview): The blob is extracted from the database, the mail message is recreated. Microsoft Outlook then opens the object.
The point here is that the item is stored in the database, not a reference to the object (Like, for example a path).
If I could work out how to take a file and create a byte array of it in memory then I think that will help.
I hope this explains my goal a little better.
Any Ideas for this would be greatly appreciated.
Thanks,
NL
This is off of the top of my head, so check this first,
Dim myFileStream As New System.IO.FileStream(path, IO.FileMode.Open, IO.FileAccess.Read)
Dim myArray(fs.Length) As Byte myFileStream.Read(myArray, 0, myFileStream.Length)
myFileStream.Close()

Hi Joe.
Been working on the answer. I managed to get it working for a single file (Not for emails), however, I've hit an issue and wander if you could help.
The following section of code takes a big binary stream in the form of byte(), called ConsultationObject. This item contains the binary copy of the file that we are going to store in the database. I need to split up the item into batches if it exceeds the length of a blob (indicated by maxBLOBsize).
The issue is that when code execution gets to BatchData.Clear command, the BatchData item is 'Nothing'. The code then bombs out without an error message or anything (which appears to be typical of .NET). I need to know how to make it equal an empty array, or at least something other than 'Nothing'.
The error that appears is "Referenced 'BatchData' has a value of 'Nothing'."
If I remove the .Clear command it bombs out at the BatchData(j) = readItem line because Batchdata is still 'Nothing'.
Regards,
NL.
Private
Sub CreateConsultationEventObjectItem(_
ByVal ConsultationEventID As Int64, _
ByVal Objectfilename As String, _
ByVal ObjectTypeDescription As String, _
ByRef ConsultationObject As Byte(), _
ByVal ConsultationObjectLength As Int64)
'Purpose: Saves the consultationeventobject to the table
' and updates the list of items
'Notes: In the table Object_Sequence_ID contains the item's sequence number
' and Object_ID_Max contains the item's Max sequence number
' so, for example if the item is 67000 bytes, then the first
' 65535 bytes will be held in the item who's sequence number is 1,
' and the next 1,465 bytes will be held in the next item which has
' a sequence number of 2. Both items will have a Object_Sequence_ID_Total
' value of 2 which states that there are 2 items which together hold the
' actual item itself. Dim MaxBLOBSize As Long = 65535 ' The maximum size of an item that
' can be stored in a row. (Zero-based) 'MySQL will only store a maximum of 65KB in a BLOB, (65535 bytes)
'so we need to divide the number of bytes in ConsultationObject by 65535
'to return the number of records that we need in order to save the file Dim NoOfRowsRequired As Int64 = CLng(ConsultationObjectLength / MaxBLOBSize) 'show the wait cursor
Me.Cursor.Current = Cursors.WaitCursor
Me.Cursor.Show() 'We need to get the Object_Sequence_ID_Total by calculating how many
If (ConsultationObjectLength Mod (MaxBLOBSize + 1)) > 0 Then 'if we can't completely divide the byte array by the MaxBLOBSize
'(+1 because it is zero-based), then we need to add an extra item
'onto the calculation to retain the last bytes of the item
NoOfRowsRequired = NoOfRowsRequired + 1 End If Dim BatchData As Byte() 'temporary store of each batch of data
Dim CurrentBytePos As Long = 0 'the current position of the byte we are looking at
Dim readItem As Byte 'Insert each new row
For i As Long = 0 To NoOfRowsRequired - 1 'clear the current batch array
BatchData.Clear(BatchData, 0, MaxBLOBSize - 1) 'Put the first MaxBLOBSize-bytes into the first/next item.
For j As Long = 0 To MaxBLOBSize
readItem = ConsultationObject((i * MaxBLOBSize) + j)
BatchData(j) = readItem
Next Me.DsConsultationEventObject1.consultationeventobject.AddconsultationeventobjectRow( CurrentEventID, _
i + 1, _
NoOfRowsRequired, _
Objectfilename, _
ObjectTypeDescription, _
BatchData, _
MySQL_Loginname, _
GetCurrentTime) Next Call MysqlModule.UpdateChanges_Table(Me.DsConsultationEventObject1, _
Me.BindingContext(Me.DsConsultationEventObject1, "consultationeventobject"), _
"consultationeventobject")
Me.DsConsultationEventObject1.AcceptChanges() 'restore the cursor Me.Cursor.Current = Cursors.Default
Me.Cursor.Show() ' Call PopulateEventObjectList() End Sub Your problem lies with your declaration of your array. You declare an array of Byte but it is a zero length array, you need to specify size.
Dim BatchData As Byte() 'temporary store of each batch of data <- no size specified
Dim CurrentBytePos As Long = 0 'the current position of the byte we are looking at
Dim readItem As Byte
'Insert each new row
For i As Long = 0 To NoOfRowsRequired - 1 'no need to clear the array because there is nothing in it
'BatchData.Clear(BatchData, 0, MaxBLOBSize - 1) 'Put the first MaxBLOBSize-bytes into the first/next item.
For j As Long = 0 To MaxBLOBSize
readItem = ConsultationObject((i * MaxBLOBSize) + j)
'must redim and preserve any items in the array here
Redim Preserve BatchData(j)
BatchData(j) = readItem
NextNow if you need to clear the array you canBatchData.Clear(BatchData,0,BatchData.Length-1)
Another way to do this is to just declare the variable with the size you need:
Dim BatchData As Byte(MaxBLOBSize -1) 'temporary store of each batch of data <- array size now set
Good luck...
Hello
I'am facing the same challenge and was searching for some answers
May i ask you if you finally made it working ? Any tips or tricks for me ?
best regards