RadGrid ItemDataBound Not showing changes to first item in Grid - c#

I know I must be missing something. If I make changes to a datagriditem in the ItemDataBound event of the RadGrid the changes are not visible the first time the page loads, I don't see the changes to the DataItem until I refresh the grid via the CommandItem for refresh. I have verified that the ItemDataBound event is fired and the values that I am replacing do infact have the correct values.
background:
I have a class that creates the RadGrid. It is then instantiated and loaded into the .aspx page via the code behind for the .aspx. This is a master/detail datagrid if that makes any difference.
protected void Page_Init(object source, EventArgs e)
{
this.__activeBatchesRadGrid = ActiveBatchesRadGrid.GridDefinition("ActiveBatchesRadGrid");
this.PlaceHolder1.Controls.Add(this.__activeBatchesRadGrid);
this.__activeBatchesRadGrid.ItemDataBound += new GridItemEventHandler(ActiveBatchesRadGrid_ItemDataBound);
}
private void ActiveBatchesRadGrid_ItemDataBound(object sender, GridItemEventArgs e)
{
GridDataItem _dataItem = e.Item as GridDataItem;
if (_dataItem == null) return;
BatchStatusType _batchStatus = EnumUtils.GetValueFromName<BatchStatusType>(_dataItem["BatchStatusName"].Text);
Dictionary<BatchStatusType, BatchStatusType> _batchStatusTypes =
BatchTransitions.GetBatchStatusTransition(_batchStatus);
GridButtonColumn _btnPromote =
((GridButtonColumn) this.__activeBatchesRadGrid.MasterTableView.GetColumn("MasterPromoteRecord"));
GridButtonColumn _btnDelete =
((GridButtonColumn)this.__activeBatchesRadGrid.MasterTableView.GetColumn("MasterDeleteRecord"));
foreach (KeyValuePair<BatchStatusType, BatchStatusType> _item in _batchStatusTypes)
{
_btnPromote.Text = _item.Value.ToString();
_btnPromote.ConfirmText = string.Format("Are you sure you want to promote this batch to {0} status?",
_item.Value);
_btnDelete.Text = string.Format("Demote batch to {0} status.", _item.Key.ToString());
_btnDelete.ConfirmText = string.Format("Are you sure you want to demote this batch to {0} status?",
_item.Key);
}
}

I thought I would post the solution I put together that takes care of this problem. I do however, still believe that the proper implementation that I originally posted should work. If it works for all items other than the first datagrid row then I believe there is a shortcoming in the control.
private void ActiveBatchesRadGrid_ItemDataBound(object sender, GridItemEventArgs e)
{
GridDataItem _dataItem = e.Item as GridDataItem;
if (_dataItem == null) return;
if (_dataItem.KeyValues == "{}") { return; }
int _counter = 0;
Dictionary<String, String> _batchStatusTypes =
BatchTransitions.GetBatchStatusTransition(
EnumUtils.GetValueFromName<BatchStatusType>(_dataItem["BatchStatusName"].Text));
//accessing the cell content directly rather than trying to access the property of the GridEditCommandColumn
((ImageButton)(((GridEditableItem)e.Item)["MasterEditrecord"].Controls[0])).ImageUrl = "/controls/styles/images/editpencil.png";
//accessing the cell content directly rather than trying to access the property of the GridButtonColumn
ImageButton _imgbtnPromote = (ImageButton)((GridDataItem)e.Item)["MasterPromoteRecord"].Controls[0];
ImageButton _imgbtnDelete = (ImageButton)((GridDataItem)e.Item)["MasterDeleteRecord"].Controls[0];
foreach (KeyValuePair<String, String> _kvp in _batchStatusTypes)
{
if (_counter == 0)
{
const string _jqueryCode = "if(!$find('{0}').confirm('{1}', event, '{2}'))return false;";
const string _confirmText = "Are you sure you want to change the status of this batch {0}?";
_imgbtnPromote.Attributes["onclick"] = string.Format(_jqueryCode, ((Control) sender).ClientID,
string.Format(_confirmText, _kvp.Value),
_kvp.Value);
_imgbtnDelete.Attributes["onclick"] = string.Format(_jqueryCode, ((Control) sender).ClientID,
string.Format(_confirmText, _kvp.Key), _kvp.Key);
_counter++;
continue;
}
_imgbtnPromote.ImageUrl = "~/controls/styles/images/approve.png";
_imgbtnPromote.ToolTip = string.Format("{0} batch", _kvp.Value);
_imgbtnDelete.ImageUrl = "/controls/styles/images/decline.png";
_imgbtnDelete.ToolTip = string.Format("{0} batch", _kvp.Key);
}
}

Related

Resort DataGridView after adding to the bound list

I have a DataGridView that is bound to a BindingSource that is bound to a BindingList. I can sort the DataGridView by clicking on a column header, as expected. But when I drop an item onto the DataGridView, it appears at the bottom of the list rather than in its correct sorted position. I found code in a StackOverflow grid to check the grid's SortOrder and SortedColumn properties, and if they are set, then to resort the grid. However, when I put a breakpoint in the DragDrop handler, I find that SortOrder is set to None and SortedColumn is null.
Here's the DragDrop handler:
private void dgvCoils_DragDrop(object sender, DragEventArgs e)
{
int? coilStack = m_draggedCoil.Stack;
m_currentCharge.RemoveCoil(m_draggedCoil);
if (coilStack.HasValue)
{
DisplayStack(coilStack.Value);
}
if (!m_inventoryList.Any(coil => coil.Coil_id == m_draggedCoil.Coil_id))
{
m_inventoryList.Add(m_draggedCoil);
if (dgvCoils.SortOrder != SortOrder.None && dgvCoils.SortedColumn != null)
{
ListSortDirection dir = ListSortDirection.Ascending;
if (dgvCoils.SortOrder == SortOrder.Descending) dir = ListSortDirection.Descending;
dgvCoils.Sort(dgvCoils.SortedColumn, dir);
}
}
}
And here is the code where I create the list and bind the source to it:
InventorySet coilSet = new InventorySet(m_db);
coilSet.FilterOnField(coilSet.m_archived, 0);
coilSet.Open();
// coilBindingSource.DataSource = coilSet.UnderlyingTable;
while (!coilSet.IsEOF())
{
m_inventoryList.Add(coilSet.ExportData());
coilSet.MoveNext();
}
coilBindingSource.DataSource = m_inventoryList;
coilBindingSource.ResetBindings(false);
dgvCoils.Refresh();
I am not setting any Sort columns in my BindingSource object. Do I need to?
And do I need to use a BindingSource if the underlying list in a BindingList?
Edit:
In looking back through my source code, I remembered that I had to add code to my ColumnHeaderMouseClick event handler to get sorting to work. Here is that handler:
private void dgvCoils_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
string strColumnName = dgvCoils.Columns[e.ColumnIndex].DataPropertyName;
SortOrder strSortOrder = GetSortOrder(dgvCoils, e.ColumnIndex);
if (strSortOrder == SortOrder.Ascending)
{
m_inventoryList = new BindingList<InventorySetData>(m_inventoryList.OrderBy(x => typeof(InventorySetData).GetProperty(strColumnName).GetValue(x, null)).ToList());
}
else
{
m_inventoryList = new BindingList<InventorySetData>(m_inventoryList.OrderByDescending(x => typeof(InventorySetData).GetProperty(strColumnName).GetValue(x, null)).ToList());
}
dgvCoils.DataSource = m_inventoryList;
dgvCoils.Columns[e.ColumnIndex].HeaderCell.SortGlyphDirection = strSortOrder;
}
I am guessing that I am doing too much programmatically, and not letting the DataGridView do what it was designed to do.

Retain table and checked checkboxes after postback

In my webpage, I have Calendar, Table and button.
After selecting date, it will fire the databind() method of table. There are checkboxes with autopostback =true. Once checked, the Table disappears. I have no idea on how to retain the table with the checked checkboxes after post back.
protected void Page_Load(object sender, EventArgs e)
{
if (Request.QueryString.Get("Id") != null)
{
if (!IsPostBack)
{
Calendar1.Visible = false;
}
}
}
protected void Calendar1_SelectionChanged(object sender, EventArgs e)
{
Label1.Text = Calendar1.SelectedDate.ToShortDateString();
//Set datasource = (cal.selectedDate), the invoking override
// DataBind() method to create table
}
Calendar1.Visible = false;
}
I've tried to databind the table again else (IsPostBack) but i wasn't able to achieve my goals, instead, it created another table on top of the existing table
This is the method to create Table with checkboxes
public override void DataBind()
{
TableRow myTableRow = default(TableRow);
TableCell myTableCell = default(TableCell);
if (source != null && !(mDate == DateTime.MinValue))
{
for (int i = 0; i <= 23; i++)
{
foreach (DataRow row in source.Tables["Object"].Rows)
{
myTableCell = new TableCell();
CheckBox cb = new CheckBox();
cb.AutoPostBack = true;
cb.Attributes.Add("id", row["objid"].ToString());
cb.InputAttributes.Add("rowID", mDate.Date.AddHours(i).ToString());
myTableCell.Controls.Add(cb);
myTableCell.HorizontalAlign = HorizontalAlign.Center;
myTableRow.Cells.Add(myTableCell);
TimeSheetTable.Rows.Add(myTableRow);
}
}
}
else
{
throw new ArgumentException(" Invalid Date.");
}
}
Dynamically generated tables need to be regenerated on every postback. For subsequent postbacks, viewstate will be reloaded, but you have to recreate the table, cells, and controls in the same exact fashion, otherwise web forms complains about it. You need to do this during Init I believe; if checkbox checked status changed, the web forms framework will update the Checked property after load, so that will be taken care of.
I usually use a repeater or listview control as dynamic controls can be painful and the ListView is pretty flexible. Databinding takes care of rebuilding the control tree for you.

How to set the focus on the next/previous cell inside a DataGrid? Especially after calling grid.CommitEdit()?

I've a custom combobox template because of some binding stuff that won't work with the 'default' ComboBoxColumn.
To make it look 'nice' I've one template for the edit mode (a Combobox) and one for the 'normal' mode (a Label).
Now, because of that I've to commit the edit made to the combobox manually inside the CellEditEnding event
private bool changeCommitInProgress = false;
private void table_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
if (e.EditingElement is ContentPresenter && e.EditAction == DataGridEditAction.Commit)
{
if (!changeCommitInProgress)
{
changeCommitInProgress = true;
DataGrid grid = (DataGrid)sender;
grid.CommitEdit(DataGridEditingUnit.Row, false);
changeCommitInProgress = false;
}
}
}
The problem with this is, that it'll remove the focus from the entire datagrid. Just to be on the safe side, these are the only properties I changed on the datagrid (aside from the Name property and the ItemsSource):
grid.AutoGenerateColumns = false;
grid.IsSynchronizedWithCurrentItem = true;
grid.SelectionUnit = DataGridSelectionUnit.Cell;
This is a fun question. I have done similar with a nested DataList where I had to add a new row after last entry and focus on the first textbox of the newly generated row, maybe you can extrapolate my strategy to fit your situation?
protected void calcAvg(object sender, CommandEventArgs e)
{
int row = Convert.ToInt32(e.CommandArgument.ToString()) - 1;
DataListItem ActiveRow = dlMeasurements.Items[row];
// Snipped code doing stuff with current row
// Compare how many rows completed to number of rows requested
if (!(row + 1 == Convert.ToInt32(txtSample.Text)))
{
// Create new row
DataRow drNew = nextMeas.Tables[0].NewRow();
nextMeas.Tables[0].Rows.Add(drNew);
// Change item index and rebind
dlMeasurements.EditItemIndex = row + 1;
dlMeasurements.DataSource = nextMeas.Tables[0];
dlMeasurements.DataBind();
//Set focus with the Script Manager
smInspection.SetFocus((TextBox)(dlMeasurements.Items[row + 1].FindControl("txtRead1")));
}
else
{
// Otherwise close the measurements and show exit button
dlMeasurements.EditItemIndex = -1;
dlMeasurements.DataSource = nextMeas.Tables[0];
dlMeasurements.DataBind();
btnSaveAndPrint.Visible = true;
}
}
}

Textbox losing value after another buttons postback

On my page I have 3 textboxes that hold values for Title, Description, Tips and keywords. When I click on a button it inserts the values into the database. When it posts back, the values are staying in the textboxes, and this is what I want.
The next part of the page has textboxes for Question, CorrectAnswer, Wrong1, Wrong2, Wrong3. When I click on the button to insert them into the database, that works, and after the button fires its event I have those 5 textboxes have a text value of null, so I can continue on adding the question and answers.
But when that button causes its postback, the values in the first textboxes disappear, and I don't want that because I have validation on the title textbox, because you can't add any questions and answers without the title in the textbox.
So how do I keep the values in the first textboxes when the second button causes a postback?
Here is the code for the two buttons, and the btnAddQandA is the button that causes a postback..
protected void btnAddQuizTitle_Click(object sender, EventArgs e)
{
daccess.AddQuizName(tbTitle.Text, taDescription.InnerText, taTips.InnerText, tbKeywords.Text);
Session["TheQuizID"] = daccess.TheID;
string myID = (string)(Session["TheQuizID"]);
int theID = Int32.Parse(myID);
if (tbKeywords.Text != null)
{
string TheKeywordHolder = "";
foreach (ListItem LI in cblGrades.Items)
{
if (LI.Selected == true)
{
TheKeywordHolder = TheKeywordHolder + LI.Value + ",";
}
}
daccess.AddQuizKeywords(theID, tbKeywords.Text);
}
}
protected void btnAddQA_Click(object sender, EventArgs e)
{
int theID = (int)Session["TheQuizID"];
daccess.AddQuizQA(tbQuestion.Text, tbCorrect.Text, tbWrong1.Text, tbWrong2.Text, tbWrong3.Text, theID);
tbQuestion.Text = null;
tbCorrect.Text = null;
tbWrong1.Text = null;
tbWrong2.Text = null;
tbWrong3.Text = null;
}
and here is my pageload event
DataAccess daccess = new DataAccess();
protected void Page_Load(object sender, EventArgs e)
{
daccess.CblGradesDS();
cblGrades.DataSource = daccess.DsCbl;
cblGrades.DataValueField = "GradeID";
cblGrades.DataTextField = "Grade";
cblGrades.RepeatColumns = 8;
cblGrades.RepeatDirection = RepeatDirection.Horizontal;
cblGrades.DataBind();
daccess.CblSubjectsDS();
cblSubjects.DataSource = daccess.DsCbl2;
cblSubjects.DataValueField = "SubjectID";
cblSubjects.DataTextField = "SubjectName";
cblSubjects.RepeatColumns = 4;
cblSubjects.RepeatDirection = RepeatDirection.Horizontal;
cblSubjects.DataBind();
if (!IsPostBack)
{
}
}
These issues are usually caused by control IDs (UniqueIDs to be specific) that do not match before and after the postback. This causes inability of finding values in viewstate. This happens when you modify the controls collection (typically in codebehind) or when you change controls' visibility. It may also happen when you modify IDs before Page_Load event when viewstate is not yet populated. It's good to know how ASP.NET lifecycle works. http://spazzarama.com/wp-content/uploads/2009/02/aspnet_page-control-life-cycle.jpg

how do i loop through each readlistviewitem, check the value, and set it to bold?

I have a listview that is loaded with a list of objects that contain an attribute called AssigneeView which holds the date that the entry was opened. The listview's ItemTemplate has a label named "lblHeader". What I want to do is loop through the ListView.Items and check each element's AssigneeView attribute, if it is null, I want to set the lblHeader.Text to be bold (indicating it is unread).
I want to create a method that takes an attribute from the Object in the Items list called ticketID and lookup whether or not the AssigneeView field is null for that field and return a bool. So it would look something like
ForEach item in listview.Items
if(IsUnread(item.datamember.ticketID)) then
item.lblHeader.MakeBold
else
item.lblHeader.MakeNotBold
I'm not 100% on how to dig into the telerik control to get what I need to do this. Any suggestions?
UPDATE:
here's where I am at the moment:
using (var client = new QUTIService.QSVCClient())
{
var data = client.SearchTickets(this.myGuid, txtSearchString.Text, 100, chkSearchClosed.Checked).ToList();
lsvResultTickets.DataSource = data;
lsvResultTickets.DataBind();
if (data.Count == 0)
{
lblStatus.Text = "No tickets found.";
}
else
{
foreach (var item in lsvResultTickets.Items)
{
var obj = item.DataItem as QT.FullTicket;
if (TicketIsUnread(obj.OriginalTicket.TicketID))
{
//???
}
}
}
}
What you will need to do is check AssigneeView in the RowDataBound event and then set lblHeader accordingly. RowDataBound is called for each row in you datasource as it is added to the GridView.
if (e.Row.RowType == DataControlRowType.DataRow) {
if (DataBinder.Eval(e.Row.DataItem, "AssigneeView") == null) {
//Set bold
} else {
//Set normal
}
}
Ok, it turns out that I just had to drill down one more level. I didn't need to pull out another method to do the check for me. I handled this is in the item loaded event handler, here's what I ended up with:
protected void ResultItem_DataBound(object sender, RadListViewItemEventArgs e)
{
var dItem = e.Item as RadListViewDataItem;
var dObj = dItem.DataItem as QT.FullTicket;
//if no read date, mark as unread (bold)
if (dObj.AssigneeView == null)
{
var headerLabel = e.Item.FindControl("lblHeader") as Label;
headerLabel.Style.Add("Font-Weight", "Bold");
headerLabel.Style.Add("Color", "Orange");
}
}

Categories

Resources