C# Photo Viewer with Windows Forms
This is an extension of Photo Viewer on MSDN
Introduction
This is a beginner tip to learn C# and ADO .NET. What you will learn from this post is listed below:
- How to use
OpenFileDialog
to select photos from local disk - How to use
saveFileDialog
to save photos to local disk - How to store and retrieve photos from SQL Server DB
- Use of Picture Box control
Few Words about the App
This app is an extension of the MSDN tutorial to make a photo viewer using C#. What I have added is the functionality to save and retrieve the images from SQL Server 2008 R2 database. The tip was developed using .NET framework 4.5.
Tools used to develop this app include Visual Studio 2013 and SQL Server 2008 R2.
It will work with lower versions of .NET framework as well.
The app has 4 picture boxes and buttons with the following functionality:
- Add From File - Clicking on this button will open the file dialog and you can browse your local disk to display a picture of the empty picture box
- Add To File - If you want to save a picture from app into local disk, you can click on this button. When you click on this button, a check box will appear corresponding to each picture. Check the check box corresponding to the picture you want to save and click on the button again. This opens the save dialog window and you can browse to your favorite location to save the picture.
- Upload to Database - Click on the button to upload the picture to database. It works in a similar fashion as Add to File button. The only difference is that it saves it to SQL Server 2008 R2 database and not to local disk.
- Download from Database - If you want to display an image from database on your app, use this button. Clicking on the button will populate a combobox for you with picture names. You can choose a picture and it will be displayed in one of the empty picture boxes.
Using the Code
The first step is to initialize the main form. I have declared two generic lists, one of type "picturebox
" and other of type "checkbox
". The checkbox
es will be used in 1:1 mapping with picture boxes. For example, the checkbox
at index 0 will be mapped with picture box at index 0. Initialize the lists and add the controls to list. The purpose of adding them to the list is that they can be traversed easily when required.
//Declare list to store picture box and checkbox controls
List<PictureBox> listPB;
List<CheckBox> chkBoxList;
string str = string.Empty;
public Form1()
{
InitializeComponent();
listPB = new List<PictureBox>();
chkBoxList = new List<CheckBox>();
//Declare the connection string
str= "Data Source=MYPC;Initial Catalog=myDB;Integrated Security=True";
//Initialize the list
listPB.Add(pictureBox1);
listPB.Add(pictureBox2);
listPB.Add(pictureBox3);
listPB.Add(pictureBox4);
chkBoxList.Add(chkpicture1);
chkBoxList.Add(chkpicture2);
chkBoxList.Add(chkpicture3);
chkBoxList.Add(chkpicture4);
}
After initializing the file, let us write the code for the various functionality of the app.
- We will now see the code for the various buttons and try to understand how it works. We will start with Add from file button, as mentioned above. Clicking on the button will allow you to browse through your local disk and display the picture in picture box. We will be using a control here called
OpenFileDialog
control. This control opens up the file window to browse through the computer's local disk, To add this control to your app, open the toolbox and double click onOpenFileDialog
control. Another thing to take care of is the size of the picture, how the picture will be displayed on the picture box depends on the size of the picture. To make sure that the full picture is visible before displaying the image, check if the picture size is more than the size of thepicturebox
, then set thePictureBoxSizeMode
property toZoom
else it will be set asNormal
. As mentioned previously, the picture will be displayed in an empty picture box, so aforeach
loop has been added to traverse through thepicturebox
collection and check if theImage
property of thepicturebox
isnull
, it indicates that thepicturebox
is empty and picture can be added there. Let us have a look at the important properties and methods used in the below code snippet.-
openFileDialog1.ShowDialog()
- Calling this method opens the window
-
pb.Load(openFileDialog1.FileName)
- This loads the file chosen in the window to thepicturebox
private void btnAddFromFile_Click(object sender, EventArgs e) { if (openFileDialog1.ShowDialog() == DialogResult.OK) { //Loop through the picture boxes foreach (PictureBox pb in listPB) { //Find an empty picture box if (pb.Image == null) { //Load the image pb.Load(openFileDialog1.FileName); Image img = pb.Image; //Adjust the image size after loading it to Picture box if (pb.Width < img.Width && pb.Height < img.Height) { pb.SizeMode = PictureBoxSizeMode.Zoom; } else { pb.SizeMode = PictureBoxSizeMode.Normal; } break; } } } }
-
- As mentioned previously, to add pictures to file or to database when user clicks on the button,
checkbox
es will appear corresponding topicturebox
es that have images in them. The below mentioned code snippet loops through thepicturebox
collection and if the.Image
property is notnull
will make thecheckbox
visible for the correspondingpicturebox
. As mentioned previously also thecheckbox
andpicturebox
collection have 1:1 mapping.public void ShowCheckBoxes() { int count = 0; //Loop through the picture box collection to find out the picture boxes that have images, only the checkboxes for those picture boxes will be visible foreach (PictureBox img in listPB) { if (listPB[count].Image != null) { chkBoxList[count].Visible = true; } ++count; } }
To add pictures to the local disk, we will be using another control called
saveToDialog
. This control can be found in toolbox in Visual Studio under common controls. Here, adding a newSaveToDialog
from toolbox will not be required as we are creating an object of the class at run time and utilizing its properties. Same can be done in case ofOpenDialogBox
. It is left to the programmer's discretion. Let us have a look at some important methods and properties used here.- save.Filter = "Bitmap files (*.bmp)|*.bmp|JPG files (*.jpg)|*.jpg|GIF files (*.gif)|*.gif"; - This piece of code restricts the file extension that can be used while saving the picture. '|' indicates the OR symbol.
save.FilterIndex = 3;
-Filter
property decides the index of the extension that will be visible by default in thesave
dialog. It starts from1
. In our case, the extension at index3
is gif. So when user clicks the button 'gif
' extension will be visible by default.-
save.RestoreDirectory = true;
- When the save window is open, then the current directory is changed to the save window, when you close the window, the original directory that was the current directory before save window opened should be restored. This line of code helps in achieving this.
private void btnAddToFile_Click(object sender, EventArgs e) { ShowCheckBoxes(); int count = 0; foreach (CheckBox chk in chkBoxList) { if (chk.Checked) { int index = count; SaveFileDialog save = new SaveFileDialog(); save.Filter = "Bitmap files (*.bmp)|*.bmp|JPG files (*.jpg)|*.jpg|GIF files (*.gif)|*.gif"; save.FilterIndex = 3; save.RestoreDirectory = true; if (save.ShowDialog() == DialogResult.OK) { listPB[count].Image.Save(save.FileName); } } } }
- The row in DB that holds the picture is a row of type
varbinary
hence the image must be converted into byte array before it is sent to DB. The below mentioned code snippet converts the image to byte array:image = System.IO.File.ReadAllBytes(imageLocation);
Here the image location refers to the location of the image on disk and is obtained by the below mentioned code snippet:
string imageLocation = pictureBox1.ImageLocation;
The full code is shown below:private void btnUpload_Click(object sender, EventArgs e) { ShowCheckBoxes(); int count = 0; //Loop through all the picture boxes and add pictures selected by users. foreach (CheckBox chk in chkBoxList) { if (chk.Checked) { string imageLocation = pictureBox1.ImageLocation; byte[] image = null; //Convert the image into byte array for saving it to DB image = System.IO.File.ReadAllBytes(imageLocation); SqlConnection sqlCon = new SqlConnection(str); System.Data.SqlClient.SqlCommand command = new System.Data.SqlClient.SqlCommand ("insert into test(photo,name) values (@photo,@name)", sqlCon); command.Parameters.AddWithValue("@photo", image); command.Parameters.AddWithValue("@name", imageLocation); sqlCon.Open(); command.ExecuteNonQuery(); sqlCon.Close(); } ++count; } }
- To download and display pictures in
picturebox
, use the following code. The process will be done in two steps. In the first step, acombobox
will be populated with picture names and once the user chooses the picture name fromcombobox
the corresponding picture will be loaded in thepicturebox
. The code to load the picture is written in the selected index changed event ofcombobox
:private void button4_Click(object sender, EventArgs e) { SqlConnection sqlCon = new SqlConnection(str); System.Data.SqlClient.SqlCommand command = new System.Data.SqlClient.SqlCommand("select name from test", sqlCon); sqlCon.Open(); SqlDataAdapter da = new SqlDataAdapter(command); DataTable dt = new DataTable(); da.Fill(dt); sqlCon.Close(); comboBox1.DataSource = dt; comboBox1.DisplayMember = "Name"; comboBox1.ValueMember = "Name"; }
This is the selected index changed event of combo box.
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) { SqlConnection sqlCon = new SqlConnection(str); System.Data.SqlClient.SqlCommand command = new System.Data.SqlClient.SqlCommand ("select photo from test where name=@name", sqlCon); command.Parameters.AddWithValue("@name", comboBox1.SelectedValue.ToString()); sqlCon.Open(); byte[] image = (byte[])command.ExecuteScalar(); if (image != null) { sqlCon.Close(); //Save the picture from Db in the memory stream MemoryStream ms = new MemoryStream(image); //Load the picture from memory stream to picture box //pictureBox1.Image = Image.FromStream(ms); foreach (PictureBox pb in listPB) { //Find an empty picture box if (pb.Image == null) { pb.Image = Image.FromStream(ms); break; } } } }