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.
The code for each button is explained below.
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.
List<PictureBox> listPB;
List<CheckBox> chkBoxList;
string str = string.Empty;
public Form1()
{
InitializeComponent();
listPB = new List<PictureBox>();
chkBoxList = new List<CheckBox>();
str= "Data Source=MYPC;Initial Catalog=myDB;Integrated Security=True";
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 on OpenFileDialog
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 the picturebox
, then set the PictureBoxSizeMode
property to Zoom
else it will be set as Normal
. As mentioned previously, the picture will be displayed in an empty picture box, so a foreach
loop has been added to traverse through the picturebox
collection and check if the Image
property of the picturebox
is null
, it indicates that the picturebox
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 the picturebox
private void btnAddFromFile_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
foreach (PictureBox pb in listPB)
{
if (pb.Image == null)
{
pb.Load(openFileDialog1.FileName);
Image img = pb.Image;
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 to picturebox
es that have images in them. The below mentioned code snippet loops through the picturebox
collection and if the .Image
property is not null
will make the checkbox
visible for the corresponding picturebox
. As mentioned previously also the checkbox
and picturebox
collection have 1:1 mapping. public void ShowCheckBoxes()
{
int count = 0;
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 new SaveToDialog
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 of OpenDialogBox
. 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 the save
dialog. It starts from 1
. In our case, the extension at index 3
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;
foreach (CheckBox chk in chkBoxList)
{
if (chk.Checked)
{
string imageLocation = pictureBox1.ImageLocation;
byte[] image = null;
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, a combobox
will be populated with picture names and once the user chooses the picture name from combobox
the corresponding picture will be loaded in the picturebox
. The code to load the picture is written in the selected index changed event of combobox
: 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();
MemoryStream ms = new MemoryStream(image);
foreach (PictureBox pb in listPB)
{
if (pb.Image == null)
{
pb.Image = Image.FromStream(ms);
break;
}
}
}
}