Putting image in DataTable and setting table as datasource to gridview - c#

I'm having problems with putting an image in a DataTable and setting this table as datasource to gridview, I've searched everywhere, but no I had no luck.
Here is the problem:
private void populateGrid()
{
// Gets a datatable from a stored procedure
DataTable ragTable = ProjetoBO.HistoricoRAGStatusProjeto(Convert.ToInt32(Session["idProjeto"]));
int group= -1;
int cont = 1;
var table = GetDataTable(ragTable);
DataRow dataRow = table.NewRow();
foreach (DataRow row in ragTable.Rows)
{
cont++;
if (Convert.ToInt32(row[9]) != group)
{
cont = 1;
group= Convert.ToInt32(row[9]);
table.Rows.Add(dataRow);
dataRow = tabelaFinal.NewRow();
}
dataRow[0] = DateTime.Parse(row[2].ToString()).ToShortDateString();
//putting some random image just for testing purpose
dataRow[cont] = Properties.Resources.myIcon;
}
//my grid
histRagStatus.DataSource = table ;
histRagStatus.DataBind();
}
//Creates a dataTable with the columns I need
private DataTable GetDataTable(DataTable ragTable)
{
var newTable= new DataTable();
newTable.Columns.Add("Date");
foreach (DataRow row in ragTable.Rows)
{
if (!newTable.Columns.Cast<DataColumn>().Any(column => column.ColumnName.Equals(row[6].ToString())))
{
var newColumn= new DataColumn(row[6].ToString());
newTable.Columns.Add(newColumn);
}
}
return newTable;
}
I've been trying everything I can, creating a new column like var newColumn= new DataColumn(row[6].ToString(),typeof(Bitmap)); / converting to an image and putting there / changing the datatype of the column before adding to the DataTable... But no luck... I just need the right way to get an image from Properties.Resources and putting it on a DataTable, that will bind to a grid and the image will appear on the gridview...
Any help is precious to me right now =D

I'm not aware of a method for natively rendering image files (including BMP) in a GridView.
In your case, what I'd do is save that bitmap in a local file in the virtual directory. Once you have the file name, you can bind that filename to an ImageField column in the GridView.

Storing the binary Bitmap in the DataTable only works in Windows Forms with the DataGridView Control. In ASP.NET DataGrid you must reference to a image URL. The simple way is enable in your DataGrid the Event RowDataBound.
Then wire up with code to your image location.
protected void GridView1_RowDataBound(object sender, GridViewRowWEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
//Setup in your image column index. By Example setting 0
e.Row.Cells[0].Text=Server.HtmlDecode(#"<img src=""./Images/pdf.gif"" />");
}
}

Related

C# How do I copy from one data grid to another without overwriting my previous selection?

I have 2 datagrid views with one datatable. I am trying to have a button that when clicked it adds the rows from csv_datagridview to optimal_datagridview. The below works however whenever I deselect an entry in csv_datagridview and hit the button again it clears that selection. I would like to have the selection stick each time.
if (selectedRowCount <= 9)
{
List<object> destList = new List<object>();
foreach (DataGridViewRow row in csv_datagridview.SelectedRows)
destList.Add(row.DataBoundItem);
optimaldataGridView.DataSource = destList;
Thank you so much in advance :)
It is unclear what your exact problem is with the little code you show, but from your statement whenever I deselect an entry in csv_datagridview and hit the button again it clears that selection. I am guessing that if nothing is selected, the data in optimaldataGridView clears when you press the add selected button.
I will assume the csv_datagridview is bound to a table. Your posted code shows the creation of new List destList which you fill with the selected rows from the csv_datagridview. Then you set optimaldataGridView data source to the destList. One issue I see in this picture is that as soon as you leave the if (selectedRowCount <= 9) clause… destList will no longer exist. As a data source for a DataGridView on your form, I would think you would want to keep this List global as long as the form is open. Either way... you are not adding the selected rows, you are simply removing the existing rows and then adding what was selected in csv_datagridview.
I hope the code below will help. I created two DataTables, one for each DataGridView. The csv_datagridview data table is filled with some data, the second data table is left empty. Then simply add the selected rows from the csv_datagridview to the optimaldataGridView’s DataTable… Then refresh optimaldataGridView.
DataTable table1;
DataTable table2;
public Form1() {
InitializeComponent();
csv_datagridview.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
optimaldataGridView.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
table1 = GetTable("table1");
table2 = GetTable("table2");
FillTable(table1);
csv_datagridview.DataSource = table1;
optimaldataGridView.DataSource = table2;
}
private void button1_Click(object sender, EventArgs e) {
if (csv_datagridview.SelectedRows.Count > 0) {
foreach (DataGridViewRow row in csv_datagridview.SelectedRows) {
DataRowView dr = (DataRowView)row.DataBoundItem;
table2.Rows.Add(dr.Row.ItemArray[0], dr.Row.ItemArray[1], dr.Row.ItemArray[2]);
}
optimaldataGridView.Refresh();
}
}
private DataTable GetTable(string name) {
DataTable table = new DataTable(name);
table.Columns.Add("col1");
table.Columns.Add("col2");
table.Columns.Add("col3");
return table;
}
private void FillTable(DataTable table) {
for (int i = 0; i < 10; i++) {
table.Rows.Add("R" + i + "C0", "R" + i + "C1", "R" + i + "C2");
}
}
Hope this helps.
Your code is working on my side.
Created a DataTable for Datasource of csv_datagridview.
Selected some rows in this grid.
Clicked the button to copy the selected rows to the
optimaldataGridView
The selected rows are still selected.
public Form1()
{
InitializeComponent();
DataTable dt = new DataTable();
dt.ReadXml(Application.StartupPath + #"\test.xml");
csv_datagridview.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
csv_datagridview.DataSource = dt;
}
private void button1_Click(object sender, EventArgs e)
{
List<object> destList = new List<object>();
foreach (DataGridViewRow row in csv_datagridview.SelectedRows)
destList.Add(row.DataBoundItem);
optimaldataGridView.DataSource = destList;
}
Make sure you have no events attached to the grids that may affect the selection.

Formatting specific rows in a DataGridView

I have a DGV named dataGridView1 that has two columns, an image column and a string column. I also have a custom Collection of data that I use to populate the DGV. In my particular application, each row will have a specified string in the string column and one of two images in the image column. I am having trouble with displaying the correct image in the image column when the DGV populates.
This is how I am filtering the data to what I want to put in the DGV:
var match = Core.Set.Servers.Where(ServerItem => ServerItem.GameTag == text);
Currently, I am doing this to populate the DGV:
dataGridView1.AutoGenerateColumns = false;
source = new BindingSource(match,null);
dataGridView1.DataSource = source;
However, the image cells just show the default broken image icon. My icon is located in
Directory.GetCurrentDirectory() + "//Images/favorite.png";
Is there a good way using a DataTable or even a BindingSource? Each item in the collection has two useful features: ServerItem.ServerName and ServerItem.IsFavorite. The first is a string, the second is a boolean. I want the favorite icon to be displayed in the icon column of each row that has IsFavorite==true.
To show an image in a bound DataGridView based on a data value you should handle CellFormatting event of the DataGridView. I would recommend store an image in some memory structure like ImageList to avoid roundtrips to storage. Here is a snippet:
List<Row> data = new List<Row>
{
new Row { IsFavorite = true },
new Row { IsFavorite = false },
};
dataGridView1.Columns.Add(new DataGridViewImageColumn(false));
dataGridView1.Columns[0].DataPropertyName = "IsFavorite";
dataGridView1.Columns[0].DefaultCellStyle.NullValue = null;
dataGridView1.DataSource = data;
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (e.ColumnIndex == 0)
{
if (e.Value != null && e.Value is bool)
{
if ((bool)e.Value == true)
{
e.Value = imageList1.Images[0];
}
else
{
e.Value = null;
}
}
}
}
public class Row
{
public bool IsFavorite { get; set; }
}
And there is another advice: to combine a path from parts you can use Path.Combine(string[])
Hope this helps.

Gridview not retaining old values in c# and ASP.Net

I have an ASP.Net gridview which is binding properly.On edit i am editing certain fields.then after i need to edit other rows as well.But when i am trying to edit other rows the previously edited rows get reset n retain their older values.
The requirement is as such that i have to edit many rows and the on a button click i need to push all the edit values to the database
You need to maintain your GridView's datasource between postbacks.
You can do this by storing your DataTable in Cache, Session, or any persistent storage.
Upon edit of a row, save the changes to this DataTable, then rebind the Gridview (from this DataTable).
When the user clicks "save all", you can save the changed rows of the DataTable to the database.
If you need to keep track of which rows have changed, you can maintain a list of PrimaryKeys that have changed in cache or Session.
Are you checking !IsPostBack inside Page_Load event before binding the grid? If you are not binding the grid in Page_Load event, please post the code to bind the grid.
The problem with your code is,you r binding grid on page load.. so when page is loading , it can bind the values which are in database. for that write bind method on Post back and also maintain your values on sessions or Hidden Fields,when you click on save button update database with that sessions or hidden fields..
morning bryan...here is that code for getting the value from the gridview to the datatable
private void getGridInfo()
{
DataTable dt = new DataTable();
DataRow dr;
dt.Columns.Add(new System.Data.DataColumn("Select", typeof(byte)));
dt.Columns.Add(new System.Data.DataColumn("Client", typeof(string)));
dt.Columns.Add(new System.Data.DataColumn("PrincipleAmt", typeof(double)));
foreach (GridViewRow row in grdRepayment.Rows)
{
CheckBox Select = (CheckBox)row.FindControl("ChkSelect");
Label ClientName = (Label)row.FindControl("lblClientName");
Label Principal = (Label)row.FindControl("lblPricipal");
dr = dt.NewRow();
dr[0] = Convert.ToByte(Select.Checked);
dr[1] = ClientName.Text;
dr[2] = Convert.ToDouble(Principal.Text);
dt.Rows.Add(dr);
}
Session["TempTable"] = dt;
}
now here is the code for updating that session variable which holds the datatable,this must be done in RowUpdating Event of the Gridview.
protected void grdRepayment_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
DataTable myDatatable;
GridViewRow row = grdRepayment.Rows[e.RowIndex];
grdRepayment.EditIndex = -1;
if (row != null)
{
myDatatable = (DataTable)Session["TempTable"];
for (int i = 0; i < myDatatable.Rows.Count; i++)
{
if (e.RowIndex == i)
{
myDatatable.Rows[i][1] = Convert.ToString(Client);
myDatatable.Rows[i][2] = Convert.ToString(Principal);
Session["TempTable"] = myDatatable;
grdRepayment.EditIndex = -1;
grdRepayment.DataSource = myDatatable;
grdRepayment.DataBind();
}
}
}
}
and make sure you bind the grid from this session variable only in RowEditing and RowCancellingEdit Events.
Once you are done with the Editing thing simply click the button which will push the edited content to the DATABASE...
Please check you'r gridview binding method was call page load and inside of !isPostBack?
for
Void page_load()
{
if(!IsPostBack)
{
//Call GridView Binding method
}
}
protected void grdRepayment_RowEditing(object sender, GridViewEditEventArgs e)
{
grdRepayment.EditIndex = e.NewEditIndex;
myDatatable = (DataTable)Session["TempTable"];
grdRepayment.DataSource = myDatatable;
grdRepayment.DataBind();
}
This is how we need to Bind the grid in RowEditing and RowCancelingEdit

add row to a dynamic datagridview

i have a windows form where i am trying to add the path of a file usnig folderbrowserDialog
i have this code on at form load
public FileMgmt()
{
InitializeComponent();
//
// Here we create a DataTable with four columns.
//
DataTable table = new DataTable();
table.Columns.Add("Check", typeof(bool));
table.Columns.Add("Path", typeof(string));
table.Columns.Add("Date", typeof(DateTime));
table.Rows.Add(false, "", DateTime.Now);
dataGridView2.DataSource = table;
}
this is the code when i click a button to search for folders and add the path to the above gridview which already has the above row
private void AddPubPath_Button_Click(object sender, EventArgs e)
{
folderBrowserDialog1.ShowDialog();
dataGridView2.Rows.Add(false, folderBrowserDialog1.SelectedPath, DateTime.Now);
}
but i get the following error..
Rows cannot be programmatically added to the DataGridView's rows collection when the control is data-bound.
please, any suggestions
Since your DataGridView is bound to a DataTable, you'll need to update your DGV through your DT. That's what the error is telling you.
Update your button click code to the following:
private void button1_Click(object sender, EventArgs e) {
if (folderBrowserDialog1.ShowDialog() == DialogResult.OK) {
var table = (DataTable)dataGridView2.DataSource;
var newRow = table.NewRow();
newRow["Check"] = false;
newRow["Path"] = folderBrowserDialog1.SelectedPath;
newRow["Date"] = DateTime.Now;
table.Rows.Add(newRow);
}
}
This code gets the DataTable your DGV is bound to, creates an empty new row for the table, populates this new row with data and then finally adds the row to the DataTable.
I've also added code that makes sure the user actually selected a folder with your FolderBrowserDialog before attempting to add the row.
Edit in response to your question about making only the Check column editable
// Make all the columns you don't want editable read only.
table.Columns["Path"].ReadOnly = true;
table.Columns["Date"].ReadOnly = true;

Adding columns to a DataTable bound to a DataGridView does not update the view

I have a DataTable which is populated from a CSV file then, using a DataGridView the data is edited in memory. As far as I understand the programmatic editing of the data should be done on the DataTable where the user editing is done via. the DataGridView.
However when I add columns programmatically to the DataTable, it is not reflected automatically in the DataGridView and I suspect the converse is also true.
How do you keep the two concurrent? I thought the idea of data binding was that this was automatic...
Also adding rows works fine.
SOLVED:
The AutoGeneratedColumns was set to false in the designer code despite being true in the properties dialog (and set explicitly in the code). The initial columns were generated programmatically and so should not have appeared however this was not picked up on since the designer code also continued to generate 'designed in' columns that were originally used for debugging.
Moral: Check the autogenerated code!
In addition to this, see this post and this post
This doesn't sound right. To test it out, I wrote a simple app, that creates a DataTable and adds some data to it.
On the button1.Click it binds the table to the DataGridView.
Then, I added a second button, which when clicked, adds another column to the underlying DataTable.
When I tested it, and I clicked the second button, the grid immedialtey reflected the update.
To test the reverse, I added a third button which pops up a dialog with a DataGridView that gets bound to the same DataTable. At runtime, I then added some values to the first DataGridView, and when I clicked the button to bring up the dialog, the changes were reflected.
My point is, they are supposed to stay concurrent. Mark may be right when he suggested you check if AutoGenerateColumns is set to true. You don't need to call DataBind though, that's only for a DataGridView on the web. Maybe you can post of what you're doing, because this SHOULD work.
How I tested it:
DataTable table = new DataTable();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
table.Columns.Add("Name");
table.Columns.Add("Age", typeof(int));
table.Rows.Add("Alex", 26);
table.Rows.Add("Jim", 36);
table.Rows.Add("Bob", 34);
table.Rows.Add("Mike", 47);
table.Rows.Add("Joe", 61);
this.dataGridView1.DataSource = table;
}
private void button2_Click(object sender, EventArgs e)
{
table.Columns.Add("Height", typeof(int));
foreach (DataRow row in table.Rows)
{
row["Height"] = 100;
}
}
private void button3_Click(object sender, EventArgs e)
{
GridViewer g = new GridViewer { DataSource = table };
g.ShowDialog();
}
public partial class GridViewer : Form //just has a DataGridView on it
{
public GridViewer()
{
InitializeComponent();
}
public object DataSource
{
get { return this.dataGridView1.DataSource; }
set { this.dataGridView1.DataSource = value; }
}
}
Is AutoGenerateColumns set to true? If you are making changes after the initial Binding you'll also have to call DataBind() to rebind the changed datasource. I know this is true for an AJAX callback, I think it is true for a WinForms control PostBack.
Here is another solution which you dont need to assign a "name" to the data grid, so that the data grid can be a template element.
(In my case, data grid is a template element inside TabControl.ContentTemplate)
The key to show the new column (added programmatically after the initial binding) is forcing the datagrid to refresh.
From the answer in Force WPF DataGrid to regenerate itself, Andres suggested setting AutoGenerateColumns from false to true will force datagrid to refresh.
Which means I simply need to:
Bind the AutoGenerateColumns to a property of my object
Set the propery to false before adding column
Set the propery to true after added column.
Here is the code:
XAML:
<DataGrid AutoGenerateColumns="{Binding toggleToRefresh}"
ItemsSource="{Binding dataTable}"
/>
C#:
public class MyTabItem : ObservableObject
{
private DataTable _dataTable = new DataTable();
public DataTable dataTable
{
get { return _dataTable; }
}
private bool _toggleToRefresh = true;
public bool toggleToRefresh
{
get { return _toggleToRefresh; }
set
{
if (_toggleToRefresh != value)
{
_toggleToRefresh = value;
RaisePropertyChanged("toggleToRefresh");
}
}
}
public void addDTColumn()
{
toggleToRefresh = false;
string newColumnName = "x" + dataTable.Columns.Count.ToString();
dataTable.Columns.Add(newColumnName, typeof(double));
foreach (DataRow row in dataTable.Rows)
{
row[newColumnName] = 0.0;
}
toggleToRefresh = true;
}
public void addDTRow()
{
var row = dataTable.NewRow();
foreach (DataColumn col in dataTable.Columns)
{
row[col.ColumnName] = 0.0;
}
dataTable.Rows.Add(row);
}
}
Hope this help :)
I had the same issue and I issued a DataBind(). It's not the silver bullet for everything, but it's what helped me in a few cases. I had to put it in before capturing information through a DataView, after the EditCommand and UpdateCommand events immediately after the EditItemIndex statement,
protected void datalistUWSolutions_EditCommand(object source, DataListCommandEventArgs e)
{
datalistUWSolutions.EditItemIndex = e.Item.ItemIndex;
datalistUWSolutions.DataBind(); // refresh the grid.
}
and
protected void datalistUWSolutions_UpdateCommand(object source, DataListCommandEventArgs e)
{
objDSSolutions.UpdateParameters["Name"].DefaultValue = ((Label)e.Item.FindControl("lblSolutionName")).Text;
objDSSolutions.UpdateParameters["PriorityOrder"].DefaultValue = ((Label)e.Item.FindControl("lblOrder")).Text;
objDSSolutions.UpdateParameters["Value"].DefaultValue = ((TextBox)e.Item.FindControl("txtSolutionValue")).Text;
objDSSolutions.Update();
datalistUWSolutions.EditItemIndex = -1; // Release the edited record
datalistUWSolutions.DataBind(); // Redind the records for refesh the control
}

Categories

Resources