I have a datatable that I bind to a gridview. The columns are variable so I'd like to take advantage of AutoGeneratedColumns. I'd like to bind an image in certain condtions. What do I need to do?
void GridView1_RowCreated(object sender, System.Web.UI.WebControls.GridViewRowEventArgs e)
{
DataRowView drv = e.Row.DataItem as DataRowView;
if (drv != null)
drv[1] = new HtmlImage() { Src = "add.png" };
}
It sounds like the AutoGeneratedColumns property won't help you here because column types apply to the whole GridView; they are not calculated per-row.
You might be able to use a TemplateField with databinding to conditionally format the field for each row without writing any code.
If that doesn't get it done for you, I suppose you will have to write code. Bear in mind that the RowCreated event always fires (event on postback) when a row is created, but will only give you a non-null DataItem (e.Row.DataItem) when the GridView actually goes to its DataSource for databinding; if the GridView has cached its rendered state (in ViewState), the data item will be null. At that point, you would only be able to access the row's primary key fields by doing something like this: var keys = myGridView.DataKeys[rowIndex]; (The primary key fields are determined by the value you give the GridView's DataKeyNames property, and are stored in ViewState so that you can access them on postback.)
You would also be careful when modifying a column that is some type of DataBoundField (as most Fields are); since the RowDataBound event happens after the RowCreated event, any manual changes to the content of a row/cell you make in the RowCreated event handler are going to be clobbered by databinding when RowDataBound is fired.
That said, RowDataBound is probably the event you want.
The RowDataBound event will always give you a non-null DataItem, but only fires when real databinding happens (as opposed to "binding" from ViewState); so typically this event does not fire at all on postbacks. That's OK, though, since the GridView will remember its state for you.
If you must use code, it should probably look something like this:
//don't forget to attach this event handler, either in markup
//on the GridView control, in code (say, in the Page_Init event handler.)
protected void GridView1_RowDataBound(object sender, System.Web.UI.WebControls.GridViewRowEventArgs e)
{
//HtmlImage gives you a plain-vanilla <img> tag in the HTML.
//If you need to handle some server side events (such as Click)
//for the image, use a System.Web.UI.WebControls.Image control
//instead.
HtmlImage img = new HtmlImage() { Src = "path/to/image.jpg" };
e.Row.Cells[1].Controls.Add(img);
}
But, seriously, check out TemplateField first.
You can use RowDataBound event to process each row:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DataRowView drv = e.Row.DataItem as DataRowView;
if (drv != null)
{
// your code here...
}
}
}
For more information about this event see here
This should work, it uses the controls of the actual cell:
void GridView1_RowCreated(object sender, System.Web.UI.WebControls.GridViewRowEventArgs e)
{
HtmlImage img = new HtmlImage() { Src = "add.png" };
e.Row.Cells[1].Controls.Add(img);
}
Related
I have a DevExpress.XtraGrid.GridControl which has a column using DevExpress.XtraEditors.Repository.RepositoryItemLookUpEdit as cell editors.
When I select an item from the LookUpEdit, this does not cause any validation but does nothing until I click anywhere to make the Grid lose focus.
My desired behaviour would be that changing the LookUpEdit's selection immediately triggers a row validation event of the Grid.
How could this be achieved?
The official DevExpress Documentation tells to call the GridView's UpdateCurrentRow method:
There may be cases when you need to implement row validation. [...] To do so, handle the ColumnView.ValidateRow event. Note that you can also initiate row validation manually by calling the ColumnView.UpdateCurrentRow method.
I did this in the GridView's ValidatingEditor event handler:
private void gridView1_ValidatingEditor(object sender,BaseContainerValidateEditorEventArgs e)
{
(sender as GridView).UpdateCurrentRow();
}
However, now I can't add new rows to the Grid any more as end-user.
What would be the correct approach?
Update:
I am now listening to the GridView's CellValueChanging event and handling it like this:
private void gridView_CellValueChanging(object sender, CellValueChangedEventArgs e)
{
GridView gv = (sender as GridView);
gv.CellValueChanging -= gridView_CellValueChanging; // detach this event handler
gv.ActiveEditor.EditValue = e.Value;
gv.CellValueChanging += gridView_CellValueChanging; // re-attach handler
gv.CloseEditor();
}
I am sure this is not the way how one should do it, but it works for existing rows. However, it does not work on the "new row" - I still have to click anywhere else to apply changes that create a new entry. I want a new row to be created as soon as any cell of the "new row" got edited.
The editor in the cell is still open, you have to close it.
private void lookup_Closed(object sender, EventArgs e)
{
gvMyGrid.CloseEditor();
gvMyGrid.UpdateCurrentRow();
}
If I just drop a gridview on my page (AutoGenerateColumns = true) and then wire up a datasource on the code-behind, is there a way to get a click event to occur in each cell for certain columns? I know I can add buttons,checkboxes, etc from designer. I was just wondering if I can do it quick and easy with AutoGenerateColumns on.
void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DataControlFieldCell c = e.Row.Cells[2] as DataControlFieldCell;
//Maybe somehow put a click event here.
}
}
You can add client-side onclick event and pass cell's (TD) ID there:
c.Attributes["onclick"] = "myJSfunction('" + c.ClientID + "')";
And perform some logic on client side, calling server if needed either via some Button/LinkButton click() method, calling __doPostBack() on some other control or even making AJAX call.
I need to find a RowIndex of the current row by selecting anywhere on the Gridview without SelectCommand. Basically i need it because i am creating a method which will return the Object depending on the DataKey of the SelectedRow. And i am calling it everywhere on the Page and i do not want to write the same code again an again.
Here is what i have.
On RowDataBound
protected void gvOrders_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
var dataKey = gvOrders.DataKeys[e.Row.RowIndex];
if (dataKey == null)
return;
int orderId = AlwaysConvert.ToInt(dataKey["OrderId"]);
Order cncOrder = OrderDataSource.Load(orderId);
// do some work
}
}
Now i have a 3 CheckBox column in gridview, so whenever i check the CheckBox state i am doing the following and load the Object again and do some database work.
On CheckBox Change Event
protected void cbIsReceived_CheckedChanged(object sender, EventArgs e)
{
GridViewRow row = ((GridViewRow)((CheckBox)sender).NamingContainer);
var dataKey = gvOrders.DataKeys[row.RowIndex];
if (dataKey == null)
return null;
int orderId = AlwaysConvert.ToInt(dataKey["OrderId"]);
Order cncOrder = OrderDataSource.Load(orderId);
// find the controls using the current row index
CheckBox cbIsReceived = (CheckBox)gvOrders.Rows[row.RowIndex].FindControl("cbIsReceived");
Label receivedDateText = (Label)gvOrders.Rows[row.RowIndex].FindControl("receivedDateText");
// do some work
}
As you can see in both events most of the code is to find the current RowIndex and load the Object and then do some database work.
if you notice, in both event the arguments supplied is different i.e OnRowBound its (GridViewRowEventArgs e) and OnCheckBox_CheckedChanged its (EventArgs e).
So for every CheckBox column i have to write the same code again and again.
I would like to create method where i can pass the Sender and get the current RowIndex back. I am not sure how to do that. please help.
You can route the events from all 3 CheckBoxes to the same method by either:
Just supply cbIsReceived_CheckedChanged as the event handler for
all three checkboxes OR:
If you've already generated methods to handle the events for all
the other CheckBoxes, then do this for all the auto-generated methods:
cbAnotherCheckBox_CheckedChanged(Object sender, EventArgs e)
{
// call the first method you've already written:
cbIsReceived_CheckedChanged(sender, e);
}
Edit:
If there are different operations for each of the CheckBoxes, then loop through the rows to get the particular CheckBox that was checked and then run the operation that's specific to it.
I have a UserControl which contain GridView.I set AutoGenerateSelectButton is true for this GridView.
But it didn't work when I press Select inside UserControl.
Do you have anyidea?
You should move your event handling to the page that owns the UserControl and not in the UserControl
Inside the Page_Load of your page, add this
myUserControl.FindControl("GridView1"));
dvGrid.SelectedIndexChanged += new EventHandler(GridView1_SelectedIndexChanged);
Add the handler to the page
protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
{
//access the GridView
GridView grid = (GridView) sender;
//access the selected row
GridViewRow selectedRow = grid.SelectedRow;
//access the selected Primary key - make sure you set the DataKeyNames property of the GridView to the Record Id - in your Markup
string currentRowPrimaryKey = grid.SelectedValue;
//OR
string currentRowPrimaryKey = grid.SelectedDataKey.Value;
}
Now you have several values to play with. You can put a break point and examine the properties of the sender to have more options. Good Luck
I have a gridview control which contains an image field. However, the image url is built from several fields in my returned dataset. How do you concatenate those fields together, and at which point do I do this so that I can pass that image url do my imagefield in my gridview? I am guessing it's on the RowDataBound but I don't know how to access each of the rows in my dataset?
Thanks.
I'm not sure what you are trying to concatenate without a code example, however I would perform the concatenation before binding the gridview and store it in a private member on the class so that you can access it later in the RowDataBound event.
You can use the row data bound event to find the control within that row and set its ImageUrl property.
private string m_ConcatUrl;
protected void gridView_RowDataBound(Object sender, GridViewRowEventArgs args)
{
if(args.Row.RowType == DataControlRowType.DataRow)
{
Image imgCtrl = (Image) args.Row.FindControl("imgCtrl");
imgCtrl.ImageUrl = m_ConcatUrl;
}
}
You can use RowDataBound event to set the cell value.
void YourGridView_RowDataBound(Object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
// You can set your cell value in this
e.Row.Cells[index] // use this to set the value in the cell
}
}
In .NET 4, it would be like this:
if (e.Row.RowType == DataControlRowType.DataRow)
{
string1 = e.Row.Cells[i].Text;
}
i is the index of the particular column you want to reference (e.g. Cells[0] is column 1).
I'm not sure if it's different in 3.5 but try that.