locked
Issue with showing images RRS feed

  • Question

  • Hi so currently I'm making a program for origami artists, one feature allows users to look at existing crease patterns made by many different artists. So far I have a simple database which using the gallery users can search through it using comboboxes and a text box for the various fields. Also if the user clicks on a record it will show the crease pattern in the first picture box and an image of the origami in the second picture box. The primary data has been entered by me before hand and all the images are stored in the programs resources. The users can then add there own records to the database including the images but i need their images to show in the picture boxes when the record is clicked. To do this I created two new columns to store the image byte data used only by the records added by the user and then the image data is drawn in the picture boxes when clicked on. My problem is that I can now click on the added data storing the image data and the images will appear, however now if i try to click on the pre entered data that have their images in the resources it won't show them because since they have no image data they get stuck in the functions. I have tried to make it so they return nothing if there is no image data in that cell but it doesn't seem to be working 

    this part extracts the image data out of the database 

    Private Function FetchCreasepattern(CreasePattern As String) As Byte()
            SQl.AddParam("@CreasePattern", CreasePattern)
            SQl.ExecQuery("SELECT CreasePatternImg " &
                          "FROM GalleryTB " &
                          "WHERE ModelName=@CreasePattern")
            If Not String.IsNullOrEmpty(SQl.Exception) OrElse SQl.RecordCount < 1 Then Return Nothing
    
            Dim Buffer As Byte() = SQl.SQLDS.Tables(0).Rows(0)("CreasePatternImg")
    
            Return Buffer
    
        End Function
        Private Function FetchOrigamiImage(Origami As String) As Byte()
            SQl.AddParam("@Origami", Origami)
            SQl.ExecQuery("SELECT OrigamiImg " &
                          "FROM GalleryTB " &
                          "WHERE ModelName=@Origami")
            If Not String.IsNullOrEmpty(SQl.Exception) OrElse SQl.RecordCount < 1 Then Return Nothing
    
    
            Dim Buffer2 As Byte() = SQl.SQLDS.Tables(0).Rows(0)("OrigamiImg")
    
            Return Buffer2
    
        End Function

    This part puts them in the picture box (only part of the sub is shown) 

      Private Sub GalleryResult_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles GalleryResult.CellClick
    
            Dim Link = GalleryResult.Rows(e.RowIndex).Cells(2).Value
            Dim Link2 = GalleryResult.Rows(e.RowIndex).Cells(3).Value
            Dim Link3 = GalleryResult.Rows(e.RowIndex).Cells(1).Value
    
            Dim Buffer As Byte() = FetchCreasepattern(Link)
    
            If Buffer IsNot Nothing Then
                Using MS As New MemoryStream(Buffer, 0, Buffer.Length)
                    MS.Write(Buffer, 0, Buffer.Length)
                    CreasePatternImg.Image = Image.FromStream(MS, True)
                End Using
            End If
    
            Dim Buffer2 As Byte() = FetchOrigamiImage(Link)
    
            If Buffer2 IsNot Nothing Then
                Using MS2 As New MemoryStream(Buffer2, 0, Buffer2.Length)
                    MS2.Write(Buffer2, 0, Buffer2.Length)
                    ModelNameImg.Image = Image.FromStream(MS2, True)
                End Using
            End If
            'These show the correct image of the origami and crease pattern for each record preset in the database 
            'It check what is in a specific cell of the record and displays the right images in the pictureboxes
    
            'Alex Satsukawa_____________________________________________________________________
            If Link.ToString.Contains("Alien 2.0") And Link2.ToString.Contains("Complex") Then
                    CreasePatternImg.Image = My.Resources.Alien_2_0_CP
                    ModelNameImg.Image = My.Resources.Alien_2
                End If
                If Link.ToString.Contains("Alien") And Link2.ToString.Contains("Intermediate") Then
                    CreasePatternImg.Image = My.Resources.Alien_CP__Alex_
                    ModelNameImg.Image = My.Resources.Alien
                End If
                If Link.ToString.Contains("Baneling") Then
                    CreasePatternImg.Image = My.Resources.Baneling_CP
                    ModelNameImg.Image = My.Resources.Baneling
                End If

    This is for adding Data to the database 

     
     Private Function AddData() As Boolean
    
            Dim PaperSize As String
            PaperSize = (PaperSizeBox1.Text & Label6.Text & PaperSizeBox2.Text & Label7.Text)
            'If the boxes are empty then it will return a false and a msg box will appear saying what to enter
            If String.IsNullOrEmpty(ArtistNameTxtBox.Text) Then MsgBox("Please enter the Artist's name.") : Return False
            If String.IsNullOrEmpty(ModelNameTxtBox.Text) Then MsgBox("Please enter the Model's name.") : Return False
            If String.IsNullOrEmpty(PaperSizeBox1.Text) Then MsgBox("Please enter the recommended paper size length.") : Return False
            If String.IsNullOrEmpty(PaperSizeBox2.Text) Then MsgBox("Please enter the recommended paper size width.") : Return False
            If String.IsNullOrEmpty(OpenFileDialog1.FileName) Then MsgBox("Please select an image for the Crease Pattern.") : Return False
            If String.IsNullOrEmpty(OpenFileDialog2.FileName) Then MsgBox("Please select an image for the Origami.") : Return False
            'Takes values from text boxes and comboboxes 
            SQl.AddParam("@ArtistName", ArtistNameTxtBox.Text)
            SQl.AddParam("@ModelName", ModelNameTxtBox.Text)
            SQl.AddParam("@Difficulty", DifficultyBox.Text)
            SQl.AddParam("@Theme", ThemeBox.Text)
            SQl.AddParam("@PaperSize", PaperSize)
            'Takes raw byte data from image chosen
            Dim Img As Image = Image.FromFile(OpenFileDialog1.FileName)
            Dim Ms As New MemoryStream()
            Img.Save(Ms, Img.RawFormat)
            Dim Buffer As Byte() = Ms.GetBuffer()
            SQl.AddParam("@CPImage", Buffer)
    
            Dim Img2 As Image = Image.FromFile(OpenFileDialog2.FileName)
            Dim Ms2 As New MemoryStream()
            Img2.Save(Ms2, Img2.RawFormat)
            Dim Buffer2 As Byte() = Ms2.GetBuffer()
            SQl.AddParam("@CPImage2", Buffer2)
    
            'Adds whatever is entered into the text boxes/comboboxes to create a new record into the database 
            SQl.ExecQuery("INSERT INTO GalleryTB (ArtistName,ModelName,Difficulty,Theme,PaperSize,CreasePatternImg,OrigamiImg) " &
                            "VALUES (@ArtistName,@ModelName,@Difficulty,@Theme,@PaperSize,@CPImage,@CPImage2) ")
            If Not String.IsNullOrEmpty(SQl.Exception) Then MsgBox(SQl.Exception) : Return False
    
            Return True
        End Function
    

    I have tried if statements saying if the CreasepatternImg and OrigamiImg are NULL then take the images from the resources but it hasn't worked. Lastly screenshot to get a better understanding. 

    The record I'm clicking on is the only one I have entered through the program and as you can see it shows the images clearly(I know wrong images but it was just a test) however if I click on any of the other records the program crashes. So overall I'm not sure how to get both to work together.

    Thanks Mistry27

    Friday, March 18, 2016 1:41 PM

Answers

  • Frank,

    I put the Option Strict On in the code for the Gallery section however this part of the code shown below can not function so I assume I've put the Option Strict on in the wrong form code or I have not understood fully. 

       Private Sub GalleryResult_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles GalleryResult.CellClick
    
            Dim Link = GalleryResult.Rows(e.RowIndex).Cells(2).Value
    
            Dim CreasePatternImgPath = FetchCreasepattern(Link)
            Dim OrigamiImgPath = FetchOrigamiImage(Link)
    
            If CreasePatternImgPath IsNot Nothing And OrigamiImgPath IsNot Nothing Then
    
                CreasePatternImg.Image = Image.FromFile(CreasePatternImgPath)
                ModelNameImg.Image = Image.FromFile(OrigamiImgPath)
    
            End If

    Thanks Mistry27


    A few notes here:

    You are using implicit type declaration when you do "Dim something = <expression>".  The type of "something" will be declared as whatever type <expression> resolves to.  That's not necessarily a bad thing and it can save a lot of keystrokes over time, but if you use it, you really have to be aware of what the <expression> resolves to.  Often it is better for beginners to code with Option Implicit Off (and Option Strict On) so that the complier won't let you use implicit type declaration.

    But if you want to get used to using it, then I suggest that in the beginning, whenever you declare a variable this way, you hover your mouse over the variable name after you finish typing the line of code and ensure that the tooltip shows the expected type for the variable.

    If the above code is giving you red squiggly lines with Option Strict On, then you have made a bad assumption about one of the implicit types.  The initial problem I see is that "Link" is going to be an Object since that is the Type for Cell.Value.  Your FetchCreasepattern() and FetchOrigamaiImage() methods likely expect String parameters so Option Strict is balking on Link being an Object type.  You could probably use Link.ToString() as the method parameter to resolve the error.  Or you could use .Cells(2).Value.ToString to change the implicit type of Link.

    Also, when testing for empty strings, use String.IsNullOrEmpty() to test for both stringValue Is Nothing and stringValue.Length > 0 simultaneously.  With VS2015 you could also write that as stringValue?.Length > 0.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"



    Sunday, March 20, 2016 8:00 PM
  • Reed,

    Just to clarify here, some of what you said isn't quite correct:

    Option Strict On Option Explicit On Option Infer On Public Class Form1 Private Sub Form1_Load(sender As System.Object, _ e As System.EventArgs) Handles MyBase.Load Dim x = "1" Dim s As String = " " Dim b As Boolean = String.IsNullOrEmpty(s) ' b returns False Stop End Sub End Class


    Option Strict and Option Infer both determine whether an object has to have the "As" clause. I realize that you didn't say otherwise, but I'd like that to be clear.

    Sure it figured out that it was a string but in my mind, use of the "As" clause is a must - on everything, no exceptions.

    Yes I know, LINQ is easier with it on and I can't use anonymous types - but that's just my opinion of course.

    Also, I think that String.IsNullOrWhiteSpace is a better choice.

    For what it's worth...

    ***** ADDENDUM *****

    From this MSDN document:

    "When you set Option Strict to On, Visual Basic checks that data types are specified for all programming elements. Data types can be specified explicitly, or specified by using local type inference. Specifying data types for all your programming elements is recommended, for the following reasons:

    • It enables IntelliSense support for your variables and parameters. This enables you to see their properties and other members as you type code.

    • It enables the compiler to perform type checking. Type checking helps you find statements that can fail at run time because of type conversion errors. It also identifies calls to methods on objects that do not support those methods.

    • It speeds up the execution of code. One reason for this is that if you do not specify a data type for a programming element, the Visual Basic compiler assigns it the Object type. Compiled code might have to convert back and forth between Object and other data types, which reduces performance."


    Knowledge rests not upon truth alone, but upon error also. Carl Jung


    Sunday, March 20, 2016 8:15 PM

All replies

  • M,

    Here's what I think you might consider doing: Have your program create (if it doesn't exist) the program's ApplicationData path and then set up a routine that will extract those images from resources and put them in that directory.

    When your user adds their own, those also will be stored locally in that directory, so they're all in one place; if one works, they all do.

    I'd do all of this with my own class(es) - and I'm not a database guy - but I'm sure it could be set up to be done using a database also.

    Food for thought. :)


    Knowledge rests not upon truth alone, but upon error also. Carl Jung

    Friday, March 18, 2016 5:35 PM
  • This is problematic:

     Using MS2 As New MemoryStream(Buffer2, 0, Buffer2.Length)
                    MS2.Write(Buffer2, 0, Buffer2.Length)
                    ModelNameImg.Image = Image.FromStream(MS2, True)
                End Using

    It likely causes a memory leak.  The stream passed to Image.FromStream must remain open for the lifetime of the image so the Using block can't be disposing the stream.

    What I would suggest is that you modify the database to hold only a path to the image files.  The images themselves can then live in multiple places - the application resources and any folders specified by the user.  If the database record contains a complete path, then you open the image from that path.  If the database record only contains an image name (no file extension or path information) then you open the image from the resources.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Friday, March 18, 2016 6:18 PM
  • This is problematic:

     Using MS2 As New MemoryStream(Buffer2, 0, Buffer2.Length)
                    MS2.Write(Buffer2, 0, Buffer2.Length)
                    ModelNameImg.Image = Image.FromStream(MS2, True)
                End Using

    It likely causes a memory leak.  The stream passed to Image.FromStream must remain open for the lifetime of the image so the Using block can't be disposing the stream.

    What I would suggest is that you modify the database to hold only a path to the image files.  The images themselves can then live in multiple places - the application resources and any folders specified by the user.  If the database record contains a complete path, then you open the image from that path.  If the database record only contains an image name (no file extension or path information) then you open the image from the resources.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Being honest, I didn't look at any of the code, but you're right about that.

    I'm not fond of using the resources or a byte array in the data - I'd put it on a website and have the program download them to a local directory. In all cases though, the data would have a local file path, not the image data itself.


    Knowledge rests not upon truth alone, but upon error also. Carl Jung

    Friday, March 18, 2016 6:30 PM
  • I am working with something similar right now. I decided to stop using byte arrays and memory streams and instead use a binding source.

    Dim BS As New BindingSource

    Private Sub AddEmp_Load(sender As Object, e As EventArgs) Handles MyBase.Load BS.DataSource = YourDataTable YourPicBox.DataBindings.Add("image", BS, "yourphoto", True) End Sub Private Sub btn_update_Click(sender As Object, e As EventArgs) Handles btn_update.Click Me.Validate() Me.BS.EndEdit() YourDataAdapter.Update(YourDataTable) End Sub

    It is a bit less complicated for me to understand. 


    Live as if you were going to die today, learn as if you were going to live forever.

    Friday, March 18, 2016 7:48 PM
  • Thanks for the help, I'll give that a try, one question what would I set the data type to for the columns that will hold the image paths. 

    Friday, March 18, 2016 9:26 PM
  • Thanks for the help, I'll give that a try, one question what would I set the data type to for the columns that will hold the image paths. 

    Please make it obvious who you're replying to, but the answer is that it needs to be a string (probably VarChar).

    I use classes but the concept is the same.


    Knowledge rests not upon truth alone, but upon error also. Carl Jung

    Friday, March 18, 2016 9:29 PM
  • Frank,

     (I completely forgot put that sorry) Ah okay thank you I'll give this image path way a try. The project is a school project with a big document behind it so if i did take away the database I'd have to change a lot of the documentation and unfortunately I don't have too much time left and this is the last part of my program I need to sort out.

    Thanks Mistry27

    Friday, March 18, 2016 9:50 PM
  • M,

    Here's what I think you might consider doing: Have your program create (if it doesn't exist) the program's ApplicationData path and then set up a routine that will extract those images from resources and put them in that directory.

    When your user adds their own, those also will be stored locally in that directory, so they're all in one place; if one works, they all do.

    I'd do all of this with my own class(es) - and I'm not a database guy - but I'm sure it could be set up to be done using a database also.

    Food for thought. :)


    Knowledge rests not upon truth alone, but upon error also. Carl Jung

    Frank, the only thing I don't like about doing this is that you have to rely on a shared folder if the application is to be distributed among several users, and another layer of security. Also if say you have other applications not made with .NET you would have to recreate the image/path constructor. Storing the image in a database I find to be very convenient.

    Live as if you were going to die today, learn as if you were going to live forever.

    Saturday, March 19, 2016 2:15 PM

  • Frank, the only thing I don't like about doing this is that you have to rely on a shared folder if the application is to be distributed among several users, and another layer of security. Also if say you have other applications not made with .NET you would have to recreate the image/path constructor. Storing the image in a database I find to be very convenient.

    Live as if you were going to die today, learn as if you were going to live forever.

    There was no indication that this was shared.

    If it were, I'd still make it local for that user and use a website for "sharing", then there's no limitations at all, but the user can still access their own images (and the ones from the program) quite quickly and easily without the slog of creating a memorystream, and from that, a bitmap.


    Knowledge rests not upon truth alone, but upon error also. Carl Jung

    Saturday, March 19, 2016 2:22 PM

  • There was no indication that this was shared.

    If it were, I'd still make it local for that user and use a website for "sharing", then there's no limitations at all, but the user can still access their own images (and the ones from the program) quite quickly and easily without the slog of creating a memorystream, and from that, a bitmap.


    Knowledge rests not upon truth alone, but upon error also. Carl Jung

    Another drawback would be showing the image in a datagridview or like control. You would need to create the  datagridviewimagecolumn manually and set the image from the path column. Where storing in the database you dont have to do anything outside of  binding to the table. I am not sure at this point in my experience why you would not use binding source.

    Live as if you were going to die today, learn as if you were going to live forever.

    Saturday, March 19, 2016 4:22 PM

  • Another drawback would be showing the image in a datagridview or like control. You would need to create the  datagridviewimagecolumn manually and set the image from the path column. Where storing in the database you dont have to do anything outside of  binding to the table. I am not sure at this point in my experience why you would not use binding source.

    Live as if you were going to die today, learn as if you were going to live forever.

    There are drawbacks to any approach.

    For me though, I'd have the images in local files.

    I don't use databases but I can create a class that would mimic one, including the image data (byte array). I don't because I think it overly bloats it for no real good reason. Every now and then there's a good reason - like serializing it all to a single binary file - but that's about the only exception I'd make to that (and even then, I'd think through how else I might could accomplish it).


    Knowledge rests not upon truth alone, but upon error also. Carl Jung



    Saturday, March 19, 2016 4:28 PM
  • When you say overly bloats, I assume this is a concern of row byte size in the database? I appreciate the conversation.

    Live as if you were going to die today, learn as if you were going to live forever.

    Saturday, March 19, 2016 4:34 PM
  • When you say overly bloats, I assume this is a concern of row byte size in the database? I appreciate the conversation.

    Live as if you were going to die today, learn as if you were going to live forever.

    Yes, exactly.

    Particularly true with the size of the images from today's various means of photographing. Even the default these days are a few megs per picture.

    It's really preference more than anything though. There's nothing "wrong" with having it as part of the data, per se, but I'd look for some other way to do it - like a website. The issue there is internet connectivity of course.


    Knowledge rests not upon truth alone, but upon error also. Carl Jung

    Saturday, March 19, 2016 4:39 PM
  • When you say overly bloats, I assume this is a concern of row byte size in the database? I appreciate the conversation.


    Live as if you were going to die today, learn as if you were going to live forever.

    Yes, exactly.

    Particularly true with the size of the images from today's various means of photographing. Even the default these days are a few megs per picture.

    It's really preference more than anything though. There's nothing "wrong" with having it as part of the data, per se, but I'd look for some other way to do it - like a website. The issue there is internet connectivity of course.


    Knowledge rests not upon truth alone, but upon error also. Carl Jung

    Certainly I am not saying any way is wrong or right, most things seem to be a matter of preference. Most of us I can assume try for the most efficient methods possible taking into consideration any other method which could depend on the process, the idea I guess is to stay 5 steps in head of yourself. My preference in this matter is no matter where you put the image it is going to take up 5mb, unless you're using an express edition of sql server or other DB with license restrictions I say let grow! terabytes are cheap! I know mysql server will swallow the images and beg for more.

    Live as if you were going to die today, learn as if you were going to live forever.

    Saturday, March 19, 2016 4:58 PM
  • GT,

    You're right in that it has to be somewhere and it'll take up x bytes to do it no matter what (notwithstanding compression).

    To each their own. :)


    Knowledge rests not upon truth alone, but upon error also. Carl Jung

    Saturday, March 19, 2016 5:03 PM
  • ...

    Certainly I am not saying any way is wrong or right, most things seem to be a matter of preference. Most of us I can assume try for the most efficient methods possible taking into consideration any other method which could depend on the process, the idea I guess is to stay 5 steps in head of yourself. My preference in this matter is no matter where you put the image it is going to take up 5mb, unless you're using an express edition of sql server or other DB with license restrictions I say let grow! terabytes are cheap! I know mysql server will swallow the images and beg for more.

    Live as if you were going to die today, learn as if you were going to live forever.

    Hi Gtripodi,

    We're creating a lengthy side discussion here in someone else's thread which is generally frowned upon... it is typically better to start your own thread with a link to the one that sparked your side-discussion.

    I thought it might be important to point out that while storage is generally cheap, database server resources may not  be.  A database server is liable to have high-speed SSDs in an array where it is more expensive to expand than in say a web server using standard spindle drives.  Also, the more work a database server is expected to do often means the more memory it is going to require (which isn't 2GB vs 4GB like a desktop but more like 16GB vs 40GB).  Granted, a lot of this depends on what else the server might be doing, but that's another important consideration for a database server... they often do many other things.

    Also, large byte array in SQL isn't going to be stored with the row... the row will just contain a pointer to blob storage.  So the database has to go through extra work to extract the data.  This can be significantly more overhead for the server than simply reading a file from the file system.

    Wire-time is another consideration.  In this case, filling the datatable means pulling all of those images during the Fill operation.  What if the user will only ever click on one or two records during their session using the software?  That means you potentially transferred dozens of other images that were never needed.  As the application's data grows, the time that the initial load of the form takes will also grow.  Because the Fill operation pulls every image you may reach a point where filtering is necessary to limit the result set.  And then you have to implement some kind of paging to get to the remaining results.  But none of that would be necessary if you were only passing path-pointers to images... it would likely take tens of thousands of records to reach a slowdown where paging was necessary.  With large images in every row it might only take hundreds (or less) rows before you saw a slow down.

    If you are storing a tiny image (like a thumbnail) within each record, and you know you will use that image whenever the record is accessed, then it might be preferable to store the image directly in the database.

    But in many cases, with user-driven usage and in order to best support scalability, it is better to store the path to the image rather than the image itself.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Saturday, March 19, 2016 6:19 PM
  • Thanks for the help, I'll give that a try, one question what would I set the data type to for the columns that will hold the image paths. 

    -EDIT-

    Ha!  I misread the question too!

    Yes, NVARCHAR(MAX) would probably be the type unless you were sure you could get away with a maximum length path string... like NVARCHAR(128).

    If you wanted to know what data type to use for storing the byte array then the rest of this reply would be relevant. :)

    -------------------------------------------------------------------------------------------------------

    Most likely you'll need VarBinary(Max) unless you know that all images are roughly equal in size and you can determine the max size; then you can use VarBinary([max size you determined]).

    If all images are under 8KB then they will be stored in the row itself.  If they are over 8KB then they will be stored in blob storage.  If you use the old "Image" data type, all images will be in blob storage regardless of size.

    Please see my other comment above for additional considerations with blob storage and byte arrays in SQL.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"


    Saturday, March 19, 2016 6:25 PM
  • Reed,

    To the extent that I understood it (I don't know databases, but I understand that fundamental concept), I agree completely.

    If you had 100 rows and each image (one per row) was just three megs, that DataTable now has 300 megs of data plus whatever size the other data per row has.

    300 megs+ ... for just 100 rows?

    I'd be looking for another way to do it. ;-)


    Knowledge rests not upon truth alone, but upon error also. Carl Jung

    Saturday, March 19, 2016 6:27 PM
  • Everyone, 

    So just to clear things up the final program won't actually be shared with anyone but I may end up using the "Crease Pattern maker" section for my own origami related use. As for my progress I have made it so the program stores the image path in the database. Then I altered the functions so that they return the image path and now when I click on any of the records that I have put an image path for(I haven't done them all yet) the images successfully appear in the picture boxes. Now Frank you mentioned an application data path to have all the images in one place and having the program store them in a local directory I'm still a bit confused (or just misunderstanding) as to how to do this since obviously not only do the pre-inserted records need to have the images stored there but also the images added by the user

    Thanks Mistry27

    Saturday, March 19, 2016 7:05 PM

  • Hi Gtripodi,

    We're creating a lengthy side discussion here in someone else's thread which is generally frowned upon... it is typically better to start your own thread with a link to the one that sparked your side-discussion.

    Reed, sorry, I figured that the extended discussion was still relevant to the op. I understand that not everybody has 128gb of server memory, and perhaps that could become a problem otherwise, I do not know. What I do know is the trade off in storing on the filesystem would increase your workload in many areas. To name a few, you now have to worry about security issues, do all your users have access to the shared folder? What if someone found this folder and deleted all your photos? You would also be adding more backup procedures other than backing up the database table. I do understand your points, along with Frank, however I cant see buying a ford ranger if I am trying to haul a yacht, instead I would buy a F450 twin-turbo powerstroke with 5inch exhaust....if you know what I mean...


    Live as if you were going to die today, learn as if you were going to live forever.

    Saturday, March 19, 2016 7:11 PM
  • Now Frank you mentioned an application data path to have all the images in one place and having the program store them in a local directory I'm still a bit confused (or just misunderstanding) as to how to do this since obviously not only do the pre-inserted records need to have the images stored there but also the images added by the user

    In your program - probably the .Load event handler - send the execution of code to a method (a sub).

    First you'll need the following imports:

    Imports System.IO.Path
    Imports System.Environment
    

    You might also want to import System.IO depending on how you want to go about doing the following.

    At the class level (form scoped level), make this declaration:

    Private programDataFolderPath As String = _
            Combine(GetFolderPath(SpecialFolder.ApplicationData), _
                    My.Application.Info.AssemblyName)
    

    In your new sub, check to see if that directory exists and if NOT, then have your program create it.

    If that's still unclear, then let me know and I'll put a real example together for you.


    Knowledge rests not upon truth alone, but upon error also. Carl Jung

    Saturday, March 19, 2016 7:13 PM
  • Mistry,

    This will make it a little more clear:

    Option Strict On Option Explicit On Option Infer Off Imports System.IO Imports System.IO.Path Imports System.Environment Public Class Form1 Private programDataFolderPath As String = _ Combine(GetFolderPath(SpecialFolder.ApplicationData), _ My.Application.Info.AssemblyName) Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load CreateProgramFolder() ' Rest of your initialization... End Sub Private Sub CreateProgramFolder() Dim di As New DirectoryInfo(programDataFolderPath) If Not di.Exists Then di.Create() End If End Sub End Class


    Please do understand that my adding the AssemblyName into the directory path isn't needed; you can set it up however else you want, but it's something I've come to do so that's what I used.


    Knowledge rests not upon truth alone, but upon error also. Carl Jung


    Saturday, March 19, 2016 7:25 PM
  • Frank,

    I put the Option Strict On in the code for the Gallery section however this part of the code shown below can not function so I assume I've put the Option Strict on in the wrong form code or I have not understood fully. 

       Private Sub GalleryResult_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles GalleryResult.CellClick
    
            Dim Link = GalleryResult.Rows(e.RowIndex).Cells(2).Value
    
            Dim CreasePatternImgPath = FetchCreasepattern(Link)
            Dim OrigamiImgPath = FetchOrigamiImage(Link)
    
            If CreasePatternImgPath IsNot Nothing And OrigamiImgPath IsNot Nothing Then
    
                CreasePatternImg.Image = Image.FromFile(CreasePatternImgPath)
                ModelNameImg.Image = Image.FromFile(OrigamiImgPath)
    
            End If

    Thanks Mistry27


    • Edited by Mistry27 Saturday, March 19, 2016 9:19 PM
    Saturday, March 19, 2016 9:07 PM
  • Frank,

    I put the Option Strict On in the code for the Gallery section however this part of the code shown below can not function so I assume I've put the Option Strict on in the wrong form code or I have not understood fully. 

       Private Sub GalleryResult_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles GalleryResult.CellClick
    
            Dim Link = GalleryResult.Rows(e.RowIndex).Cells(2).Value
    
            Dim CreasePatternImgPath = FetchCreasepattern(Link)
            Dim OrigamiImgPath = FetchOrigamiImage(Link)
    
            If CreasePatternImgPath IsNot Nothing And OrigamiImgPath IsNot Nothing Then
    
                CreasePatternImg.Image = Image.FromFile(CreasePatternImgPath)
                ModelNameImg.Image = Image.FromFile(OrigamiImgPath)
    
            End If

    Thanks Mistry27


    Sorry for the delay.

    It's up to you of course, but I would hope that you'd work through the issues of why it has those compile errors.

    For example, "Dim Link = ", to me makes no sense. What type is Link?

    If you can't work through it, then I understand, but on your next project, try starting out with those three options set that way and if you run into a bind, ask here. :)


    Knowledge rests not upon truth alone, but upon error also. Carl Jung

    Saturday, March 19, 2016 10:05 PM
  • Reed, sorry, I figured that the extended discussion was still relevant to the op. I understand that not everybody has 128gb of server memory, and perhaps that could become a problem otherwise, I do not know. What I do know is the trade off in storing on the filesystem would increase your workload in many areas. To name a few, you now have to worry about security issues, do all your users have access to the shared folder? What if someone found this folder and deleted all your photos? You would also be adding more backup procedures other than backing up the database table. I do understand your points, along with Frank, however I cant see buying a ford ranger if I am trying to haul a yacht, instead I would buy a F450 twin-turbo powerstroke with 5inch exhaust....if you know what I mean...


    Live as if you were going to die today, learn as if you were going to live forever.

    Don't worry too much.  In this case the discussion is somewhat related for others who might read this thread with a similar issue, though it probably doesn't apply to the OP's project.  In any event, it isn't so much the topic as it is that your post was addressed to another contributor, not the OP.  That's the part that turns it into a side discussion which could potentially hijack the original discussion.  Like I say, no real harm, no real foul this time.  Please take the comments for future reference.

    As for trade-offs, as Frank also conceded, there will always be pros and cons to any two solutions to the same problem.  But I'm not sure that security and retention are reasons to avoid the file share.

    Let's say this was a distributed application on a domain.  Then you might have a file share setup such that the root directory of images is read only, but each client application instance can register its own new sub folder within the share, and those folders get read-write permission for the creator and read-only permission for everyone else.  Backups would also likely be a non-issue because every bit of storage is already in the global backup set, regardless of what device it may reside on.

    Now in the case at hand, the application is local, not distributed; the database is simply a local storage medium.  The program also already includes a stock image library in it's resources, which is file-based storage.  In my mind, this makes it pretty clear that the user-provided images should also reside in the local file system and the path pointer stored in the database can be formatted to easily distinguish between the two. 


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Sunday, March 20, 2016 7:44 PM
  • Everyone, 

    So just to clear things up the final program won't actually be shared with anyone but I may end up using the "Crease Pattern maker" section for my own origami related use. As for my progress I have made it so the program stores the image path in the database. Then I altered the functions so that they return the image path and now when I click on any of the records that I have put an image path for(I haven't done them all yet) the images successfully appear in the picture boxes. Now Frank you mentioned an application data path to have all the images in one place and having the program store them in a local directory I'm still a bit confused (or just misunderstanding) as to how to do this since obviously not only do the pre-inserted records need to have the images stored there but also the images added by the user

    Thanks Mistry27

    I would let the user select the folder for the extra storage, rather than try to force it to a specific location.  Good user interface design dictates that you let the user select the storage location when it will hold files that they themselves provide.  Consider the situation where the user installs your application on their primary drive, but would prefer to keep the 100s of MB of additional images on a secondary drive.

    This isn't to say that Frank's suggestion is a bad one.  In fact there are also strong arguments for keeping all application data in the "official" app data folder.  But as noted above, in the case of user provided data (particularly when you know it could be a large amount of data) it may be better to let the user specify the location where the data should be stored.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Sunday, March 20, 2016 7:47 PM
  • Frank,

    I put the Option Strict On in the code for the Gallery section however this part of the code shown below can not function so I assume I've put the Option Strict on in the wrong form code or I have not understood fully. 

       Private Sub GalleryResult_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles GalleryResult.CellClick
    
            Dim Link = GalleryResult.Rows(e.RowIndex).Cells(2).Value
    
            Dim CreasePatternImgPath = FetchCreasepattern(Link)
            Dim OrigamiImgPath = FetchOrigamiImage(Link)
    
            If CreasePatternImgPath IsNot Nothing And OrigamiImgPath IsNot Nothing Then
    
                CreasePatternImg.Image = Image.FromFile(CreasePatternImgPath)
                ModelNameImg.Image = Image.FromFile(OrigamiImgPath)
    
            End If

    Thanks Mistry27


    A few notes here:

    You are using implicit type declaration when you do "Dim something = <expression>".  The type of "something" will be declared as whatever type <expression> resolves to.  That's not necessarily a bad thing and it can save a lot of keystrokes over time, but if you use it, you really have to be aware of what the <expression> resolves to.  Often it is better for beginners to code with Option Implicit Off (and Option Strict On) so that the complier won't let you use implicit type declaration.

    But if you want to get used to using it, then I suggest that in the beginning, whenever you declare a variable this way, you hover your mouse over the variable name after you finish typing the line of code and ensure that the tooltip shows the expected type for the variable.

    If the above code is giving you red squiggly lines with Option Strict On, then you have made a bad assumption about one of the implicit types.  The initial problem I see is that "Link" is going to be an Object since that is the Type for Cell.Value.  Your FetchCreasepattern() and FetchOrigamaiImage() methods likely expect String parameters so Option Strict is balking on Link being an Object type.  You could probably use Link.ToString() as the method parameter to resolve the error.  Or you could use .Cells(2).Value.ToString to change the implicit type of Link.

    Also, when testing for empty strings, use String.IsNullOrEmpty() to test for both stringValue Is Nothing and stringValue.Length > 0 simultaneously.  With VS2015 you could also write that as stringValue?.Length > 0.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"



    Sunday, March 20, 2016 8:00 PM
  • Reed,

    Just to clarify here, some of what you said isn't quite correct:

    Option Strict On Option Explicit On Option Infer On Public Class Form1 Private Sub Form1_Load(sender As System.Object, _ e As System.EventArgs) Handles MyBase.Load Dim x = "1" Dim s As String = " " Dim b As Boolean = String.IsNullOrEmpty(s) ' b returns False Stop End Sub End Class


    Option Strict and Option Infer both determine whether an object has to have the "As" clause. I realize that you didn't say otherwise, but I'd like that to be clear.

    Sure it figured out that it was a string but in my mind, use of the "As" clause is a must - on everything, no exceptions.

    Yes I know, LINQ is easier with it on and I can't use anonymous types - but that's just my opinion of course.

    Also, I think that String.IsNullOrWhiteSpace is a better choice.

    For what it's worth...

    ***** ADDENDUM *****

    From this MSDN document:

    "When you set Option Strict to On, Visual Basic checks that data types are specified for all programming elements. Data types can be specified explicitly, or specified by using local type inference. Specifying data types for all your programming elements is recommended, for the following reasons:

    • It enables IntelliSense support for your variables and parameters. This enables you to see their properties and other members as you type code.

    • It enables the compiler to perform type checking. Type checking helps you find statements that can fail at run time because of type conversion errors. It also identifies calls to methods on objects that do not support those methods.

    • It speeds up the execution of code. One reason for this is that if you do not specify a data type for a programming element, the Visual Basic compiler assigns it the Object type. Compiled code might have to convert back and forth between Object and other data types, which reduces performance."


    Knowledge rests not upon truth alone, but upon error also. Carl Jung


    Sunday, March 20, 2016 8:15 PM
  • Reed,

    Just to clarify here, some of what you said isn't quite correct:...


    Knowledge rests not upon truth alone, but upon error also. Carl Jung

    Thanks Frank, good catch. I've edited the post. I forgot that without Option Strict On, Option Implicit Off (which I mistakenly referred to as Option Explicit On) won't cause a compile error, it will just resolve to Object instead of the type of <expression>.

    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Sunday, March 20, 2016 8:27 PM