Databinding PictureBox to relative path in winform - c#

I have a winform that pull data from database into a DataGridView and Databind it to several text box and a PictureBox. I have a databinding and data loading method to reload and rebind when there is change in the data as below.
private void LoadData()
{
DataTable dtDS = new System.Data.DataTable();
dtDS = prodController.GetData();
dgvProduct.DataSource = dtDS;
}
private void DataBinding()
{
txtProductID.DataBindings.Clear();
txtProductID.DataBindings.Add("Text", dgvProduct.DataSource, "ProductID");
txtProductName.DataBindings.Clear();
txtProductName.DataBindings.Add("Text", dgvProduct.DataSource, "ProductName");
...
bxImage.DataBindings.Clear();
bxImage.DataBindings.Add("ImageLocation", dgvProduct.DataSource, "ImagePath");
}
At first I stored the absoluted path of the image in the database as string and it worked fine binding the data into the control. But after that I want to only store the image name in the database, the image themselves are moved to an Image folder in the Application startup folder so that I can load the Image like this:
bxImage.Image = Image.FromFile(Application.StartupPath + #"\Image\Student\" + imagePath);
I followed Databinding a label in C# with additional text? to add like below to my DataBinding method:
var binding = new Binding("ImageLocation", dgvProduct.DataSource, "ImagePath");
binding.Format += delegate (object sentFrom, ConvertEventArgs convertEventArgs)
{
convertEventArgs.Value = Application.StartupPath + #"\Image\" + convertEventArgs.Value;
};
bxImage.DataBindings.Add(binding);
It worked as first but after each time the LoadData and DataBinding are called the string keep adding onto each other making the path invalid. Even if I called the DataBinding clear and reset the format it still adding each time the methods is called. Is there a way to properly do this or should I use CellClicked method of DataGridView to get the image to load into the PictureBox?

I know this is long overdue but I should update the answer for anyone who stumble upon this problem the same as me. Thanks #TaW for the answer. In the binding.Format change the code to this:
String path = convertEventArgs.Value.ToString();
if (!path.StartsWith(Application.StartupPath + #"\Image\"))
{
convertEventArgs.Value = Application.StartupPath + #"\Image\" + convertEventArgs.Value;
}
This should prevent the string to be added each time the DataBinding is called and help bind the data to the control properly.

Related

Add extra text while databinding

I'm trying to add some extra text to the following code but it doesn't seem to work whatever I do. The information I want to show in a label comes from a DataBinding. But I can't manipulate it like a usual string
lblPower.DataBindings.Add("Text", BindingSourceMachineProfiles, nameof(MachineProfile.NominalPower));
At the moment the label only displays a number but I would like to add before the description and at the back the units.
So I would like to have e.g. "Speed" + code from above + "km/h"
How could I do this using the current code?
I have found a solution by using Binding.Format Below I have made an example of how I use it in my app.
var SpeedBinding = new Binding("Text", BindingSource);
SpeedBinding.Format += delegate (object sentFrom, ConvertEventArgs convertEventArgs)
{
convertEventArgs.Value = "Speed: " + convertEventArgs.Value + " km/h";
};
lblPower.DataBindings.Add(SpeedBinding);
This gives me nice results

How to import a picture from URL which is saved in database in existing data grid?

I have been looking for solution for days now and still have done nothing.
I have an database which, as one of the values has URL for picture, let´s say the attribute name is Picture_Link, I can show URL in data grid view but I have to show it as a picture with all other columns and rows.
In other data grid I have to show pictures directly from link that I have from app-i result.
All objects in data grid are shown via list which I import from data base (CRUD) and other one is via app-i key result.
CRUD Video = new CRUD();
List<YouTubeVideo> list = Video.GetVideosDB();
dataGridYT.DataSource = list;
This is how my view is imported.
Also I have some added columns, such as save and delete which are type image.
DataGridViewImageColumn oSaveButton = new DataGridViewImageColumn();
oSaveButton.Image = Image.FromFile("D:/save.png");
oSaveButton.Width = 50;
oSaveButton.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
dataGridYT.Columns.Add(oSaveButton);
dataGridYT.AutoGenerateColumns = false;
And CellContntClick functions which work.
Everything works except dinamic upload of images in both of data grid views.
private void dataGridYT_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (dataGridYT.Columns[e.ColumnIndex].Name == "Thumbnail")
{
e.Value = GetImageFromUrl("https://i.ytimg.com/vi/oZItXZtkmzg/default.jpg");
dataGridYT.Columns[e.ColumnIndex].DefaultCellStyle.BackColor = Color.Azure;
}
}
private object GetImageFromUrl(string url)
{
HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url);
using (HttpWebResponse httpWebReponse = (HttpWebResponse)httpWebRequest.GetResponse())
{
using (Stream stream = httpWebReponse.GetResponseStream())
{
return Image.FromStream(stream);
}
}
}
I have tried this.
Still nothing, tried to make new data grid with only one column, have copied working code from repos and that one won´t work either. But if I make whole new solution it works. Added new column also.
I have tab control, with two tabs. Each tab has one data grid view, one of the columns shows values of image url´s which I have to use to show a picture, also I need that link for saving whole row in db. I have tried with foreach loop to get each cell value with link and to add image with function in code above.
dataGridYT.CellFormatting +=
new System.Windows.Forms.DataGridViewCellFormattingEventHandler(
this.dataGridYT_CellFormatting);
This line was missing and it fixed problems from above. I goes just under the code where I have added image cells such as oSaveButton.
DataGridViewImageColumn oSaveButton = new DataGridViewImageColumn();
oSaveButton.Image = Image.FromFile("D:/YouTube_KV/save.png");
oSaveButton.Width = 50;
oSaveButton.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
dataGridYT.Columns.Add(oSaveButton);
dataGridYT.AutoGenerateColumns = false;
dataGridYT.DefaultCellStyle.WrapMode = DataGridViewTriState.True;
dataGridYT.Rows.Add(Environment.NewLine);
dataGridYT.CellFormatting +=
new System.Windows.Forms.DataGridViewCellFormattingEventHandler(
this.dataGridYT_CellFormatting);
dataGridYT.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;

How do I get the Bitmap name when I click the image in datagridview?

I am trying to click on an image in a datagridview and then write its image/file name into a textbox so I can access this from elsewhere.
First I try just a small app to make sure I can make it all work. A Dialog contains the dataviewgrid and I put a bitmap into it as below:
public ChooseFormat()
{
InitializeComponent();
dataGridView1[0,0].Value = new Bitmap(#"C:\a\eggs\grid_app\grid_app\bin\Debug\graphics\1L5HQ60.bmp");
}
Now I click on the image but all the things I have tried I cannot get hold of the file name. The closest I get is below but this returns "System.Drawing.Bitmap" and not the file name. I am sure this must just be a tweak here to make it work but I have tried teh few things I know and nothing is working.
void DataGridView1CellContentClick(object sender, DataGridViewCellEventArgs e)
{
txtbx_choice.Text = dataGridView1[0,0].Value.ToString();
}
Drilling into the cells's data in the debugger doesn't bring up any info on the source of it. Maybe I have overlooked something..
One simple solution is to store the filename in the cell's Tag property:
string fileName = #"C:\a\eggs\grid_app\grid_app\bin\Debug\graphics\1L5HQ60.bmp";
dataGridView1[0,0].Value = new Bitmap(fileName );
dataGridView1[0,0].Tag = fileName ;
Now you can always access it:
string displayedFile = dataGridView1[0, someRow].Tag.ToString();
I have placed a Picture Box on the same form and this how I am displaying the ImageColumn's data (an Image ) in picture box
pictureBox1.Image = (Image)dataGridView1[0, 0].Value;

C# : List image reset after close app

I'm using VS2013 to develop an windows form application with SQL Server database.
I have a column in database table to store the image name :
In my application, I creat a button to select image from my computer and save that's image to application startup path :
private void buttonX1_Click(object sender, EventArgs e)
{
try
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Filter = "Image only. | *.jpg; *.jpeg; *png; *.gif;";
dlg.InitialDirectory = #"E:\";
dlg.Multiselect = false;
string a = null;
if (dlg.ShowDialog() == DialogResult.OK)
{
string[] tmp = dlg.FileNames;
foreach (string i in tmp)
{
FileInfo fi = new FileInfo(i);
string[] xxx = i.Split('\\');
string des = Application.StartupPath + #"\Images\" + xxx[xxx.Length - 1];
string desfolder = Application.StartupPath + #"\Images\";
imagename = xxx[xxx.Length - 1].ToString();
System.IO.Directory.CreateDirectory(desfolder);
File.Delete(des);
imageuploaded.Image = Image.FromFile(dlg.FileName);
//over.
fi.CopyTo(des);
imageList1.Images.Add(imagename, Image.FromFile(des));
//Process.Start("explorer.exe", desfolder);
}
MessageBox.Show("Thành công ");
}
}
catch (Exception ex) { MessageBox.Show(ex.Message); }
}
That code will load the image from computer, save to folder "images" in startup path and add image to imagelist1, too.
After that, I have a button to insert imagename to "Images" column (in SQL server database).
I have this code to use imagelist for my grid :
public PrdMan()
{
InitializeComponent();
GridPanel panel = superGridControl1.PrimaryGrid;
GridColumn column = panel.Columns["image"];
column.EditorType = typeof(MyGridImageEditControl);
column.EditorParams = new object[] { imageList1, ImageSizeMode.Zoom };
//superGridControl1.PrimaryGrid.Columns[8].Visible = false;
//superGridControl1.PrimaryGrid.Columns[2].CellStyles = "dd/MM/yyyy";
//styleManager1.ManagerStyle = eStyle.Metro;
//
//this.Location = new Point(0, 0);
//this.Size = Screen.PrimaryScreen.WorkingArea.Size;
}
And code to load grid :
this.mPhamTableAdapter.Fill(this.beautyMaDataSet.MPham);
this.superGridControl1.PrimaryGrid.DataSource = this.beautyMaDataSet.MPham;
My problem is : When I load image, and insert it into database's "Images" columns : It's success and grid will display image. But When I close app (after published) or stop debug (in VS) then re-open ( or debug again). The grid will not display my image
even though the image was still in folder :
And imagelist have no image in list :
I don't know what is my problem. Can you support me how to :
1/ Add image from PC to startup path's folder using C# and save image name to SQL server (to bind image to grid).
2/ Bind image from startup path's folder to imagelist and use it.
Thanks for support.
I sense two problems in your code, maybe some of them cause your problem.
First, if you load a table to a DataGridView (or something else), and update the GridView with your new image, but not write back to the database manually, the modification will not save to database.
As you said,
After that, I have a button to insert imagename to "Images" column (in SQL server database). I have this code to use imagelist for my grid
I guess one reason of your problem may relative to here.
Second, you used a dialog to select an image and copy to path "APP\Images", and store name to database. How will you do when the user run you application next time? Load the table and get image names, and find those images from the path?
Please provide the relative codes to solve your problem.
BTW, if the database is local, off-line DB, and also you won't store too many records, you may consider store your image raw-data in DB, too. (I know some people do not recommend this way, but in my opinion, it's one way to solve your problem too.)

How to update listview automatically after adding a new item into DB

I'm using C# WPF MVVM. So in XAML there is a listview, which is binded to an object, used to show different information from sql database depending on tab.
For example. I have two forms: one is that shows information and another that is used to input information. How can I automatically update the listview in one form, after new information was entered in another form? Because now I have to switch tabs to get the listview updated.
binding direction for this element should be exposed to TwoWay (Mode=TwoWay)
like this:
x:Name="list"
ItemsSource="{Binding ....... , Path=........., Mode=TwoWay}}" ......
Apart from the default binding, which is one way, you can also configure binding to be two way, one way to source, and so forth. This is done by specifying the Mode property.
OneWay: Causes changes to the source property to automatically update the target property but the source does not get changed
TwoWay: Changes in the source or target automatically cause updates to the other
OneWayToSource: Causes changes to the target property to automatically update the source property but the target does not get changed
OneTime: Causes only the first time change to the source property to automatically update the target property but the source does not get changed and subsequent changes do not affect the target property
you can look this : http://msdn.microsoft.com/en-us/library/ms752347.aspx
After you enter new information into a form, try to invoke your own method, which will update your information into a list view.
So you can use some event eg. DataContentChanged or your update method can be called when u click the button which adds new data into your form.
Example of refresh method should look like this:
public void lbRefresh()
{
//create itemsList for listbox
ArrayList itemsList = new ArrayList();
//count how many information you wana to add
//here I count how many columns I have in dataGrid1
int count = dataGrid1.Columns.Count;
//for cycle to add my strings of columns headers into an itemsList
for (int i = 0; i < count; i++)
{
itemsList.Add(dataGrid1.Columns[i].Header.ToString());
}
//simply refresh my itemsList into my listBox1
listBox1.ItemsSource = itemsList;
}
EDIT: To finish and solve your problem, try to use this snippet of code:
//some btn_Click Event in one window
//(lets say, its your callback " to update" button in datagrid)
private void Button_Click_1(object sender, RoutedEventArgs e)
{
//here you doing somethin
//after your datagrid got updated, try to store the object,
//which u want to send into your eg. listbox
data[0] = data; //my stored data in array
//for better understanding, this method "Button_Click_1" is called from Window1.xaml.cs
//and I want to pass information into my another window Graph1.xaml.cs
//create "newWindow" object onto your another window and send "data" by constuctor
var newWindow = new Graph1(data); //line *
//you can call this if u want to show that window after changes applied
newWindow.Show();
}
After that your Graph1.xaml.cs should look like this:
public partial class Graph1 : Window
{//this method takes over your data u sent by line * into previous method explained
public Graph1(int[]data)
{
InitializeComponent();
//now you can direcly use your "data" or can call another method and pass your data into it
ownListBoxUpdateMethod(data);
}
private void ownListBoxUpdateMethod(int[] data)
{
//update your listbox here and its done ;-)
}

Categories