Problem:
I have a value in a database table. This value can either contain a number, or null. If its null I would like to show one group of controls. If its not null I would like to show another group of controls.
Previous Attempts:
I have tried creating the controls in the code behind depending on the value of the database. This worked. However, on postback I get a null reference exception. The control doesn't exist on postback because the page is stateless. I'm building the controls in the page_load handler (depending on the value of the table column). Since I'm creating the controls in the page_load shouldn't they exist on postback?
I also tried recreating the controls in the event handler for the button. I get a "theres already a control with this id" exception (presumably because I already created it in the page_load method).
I read a few posts about how I have to store the controls in a session. This seems like more work than it should be.
Questions:
Am I going about this the wrong way? This seems like it should have been simple but is turning into a mess.
If this is the correct way to do this, Where do I add the session information? I've been reading other posts and I'm kind of lost
Code:
int bookId;
string empName;
protected void Page_Load(object sender, EventArgs e)
{
if(int.TryParse(Request.QueryString["id"], out bookId))
{
//This is where the value in the database comes into play. If its null Book.GetCopyOwner
// returns a string with length 0
empName = Book.GetCopyOwner(bookId, Request.QueryString["owner"]);
if (empName.Trim().Length > 0)
{
CreateReturnControls();
}
else
{
CreateCheckoutControls();
}
}
}
protected void ReturnButton_Click(object sender, EventArgs e)
{
}
protected void CheckOut_Click(object sender, EventArgs e)
{
int bookId;
if (int.TryParse(Request.QueryString["id"], out bookId))
{
TextBox userId = (TextBox)this.Page.FindControl("UserId");
//WHEN I TRY TO USE THE TEXTBOX userId HERE, I GET NULL REFERENCE EXCEPTION
BookCopyStatusNode.Controls.Clear();
CreateReturnControls();
}
}
protected void CopyUpdate_Click(object sender, EventArgs e)
{
}
private void CreateCheckoutControls()
{
TextBox userId = new TextBox();
//userId.Text = "Enter Employee Number";
//userId.Attributes.Add("onclick", "this.value=''; this.onclick=null");
userId.ID = "UserId";
Button checkOut = new Button();
checkOut.Text = "Check Out";
checkOut.Click += new EventHandler(CheckOut_Click);
TableCell firstCell = new TableCell();
firstCell.Controls.Add(userId);
TableCell secondCell = new TableCell();
secondCell.Controls.Add(checkOut);
BookCopyStatusNode.Controls.Add(firstCell);
BookCopyStatusNode.Controls.Add(secondCell);
}
private void CreateReturnControls()
{
Label userMessage = new Label();
userMessage.Text = empName + " has this book checked out.";
Button returnButton = new Button();
returnButton.Text = "Return it";
returnButton.Click += new EventHandler(ReturnButton_Click);
TableCell firstCell = new TableCell();
firstCell.Controls.Add(userMessage);
TableCell secondCell = new TableCell();
secondCell.Controls.Add(returnButton);
BookCopyStatusNode.Controls.Add(firstCell);
BookCopyStatusNode.Controls.Add(secondCell);
}
It looks like you're creating a static set of controls based on the database value. Why not simply have 2 Panels that contain the controls you want and simply set their visibility to true or false:
if (!Page.IsPostBack)
{
if (int.TryParse(Request.QueryString["id"], out bookId))
{
empName = Book.GetCopyOwner(bookId, Request.QueryString["owner"]);
var display = (empName.Trim().Length > 0);
panelReturnControls.Visible = display;
panelCheckoutControls.Visible = !display;
}
}
Related
I have a small ASP web application which can be used to determine whether or not 2 users have been assigned the same seat number.
To display the results / functionality, I decided to go with an asp:Table, where each row has 2 buttons (one for each user).
The administrator can click either one of the buttons to clear that user's seat number value from the system.
Here is the code which builds the table cells:
BuildDuplicateTable (called in Page_Load)
private void BuildDuplicateTable(List<Duplicate> duplicates)
{
foreach (var dup in duplicates)
{
var row = new TableRow();
var user1cell = new TableCell();
var seatcell = new TableCell();
var user2cell = new TableCell();
var button1 = new Button();
button1.Text = $"{dup.UserOne.UserName}";
var button1cell = new TableCell();
button1cell.Controls.Add(button1);
button1.Click += new EventHandler(Test);
var button2 = new Button();
button2.Text = $"{dup.UserTwo.UserName}";
var button2cell = new TableCell();
button2cell.Controls.Add(button2);
button2.OnClientClick = "return true";
button2.Click += (sender, eventArgs) =>
{
ActiveDirectory.ClearProperty(dup.UserTwo.UserName, "extensionAttribute2");
};
user1cell.Text = dup.UserOne.UserName;
seatcell.Text = dup.UserOne.SeatNumber;
user2cell.Text = dup.UserTwo.UserName;
row.Cells.Add(button1cell);
row.Cells.Add(seatcell);
row.Cells.Add(button2cell);
MyAspTable.Rows.Add(row);
}
}
My issue is that when I click on any of the buttons, the page is simply refreshed, and the data is no longer displayed (as I am handling postback in Page_Load). My event handler never fires ... Notice that in the code above I left in 2 separate methods of attaching an event handler that I tried - neither of them works!
Duplicate
class Duplicate
{
public UserSeatNumberRelationship UserOne;
public UserSeatNumberRelationship UserTwo;
public Duplicate(UserSeatNumberRelationship userone, UserSeatNumberRelationship usertwo)
{
UserOne = userone;
UserTwo = usertwo;
}
}
UserSeatNumberRelationship
class UserSeatNumberRelationship
{
public string UserName;
public string SeatNumber;
public UserSeatNumberRelationship(string username, string seatnumber)
{
UserName = username;
SeatNumber = seatnumber;
}
}
Page_Load
protected void Page_Load(object sender, EventArgs e)
{
if (Page.IsPostBack) return;
DuplicateList = FindDuplicates();
BuildDuplicateTable(DuplicateList);
}
Test
protected void Test(object sender, EventArgs e)
{
ActiveDirectory.ClearProperty(UserName, "extensionAttribute2");
}
As ConnersFan mentioned in the comments, this was being caused by my PostBack handler in Page_Load.
So after removing this line
if (Page.IsPostBack) return;
The event handlers work fine.
My problem is that I dynamically create a table where each cell includes a linkbutton, that when clicked is supposed to remove that cell from the table.
(It is i bit more complex than that but I will not go into those details, just saying that a workaround will not do) I have read a few post on this and it usually is mentioned that the control has too be (re)made in page load or before. I have tried to run the method that runs setCellContent from both page load and page init and pre init but the _lnkBntRemoveSlotFromTable_Click method
is never called as the linkbuttons are clicked. And I am beginning to wonder there is something else wrong than just when the controls are created/recreated.
For each cell the table consist of, this is what is done:
private TableCell setCellContent(string day, DateTime timeOfDay){
TableCell newCell = new TableCell();
LinkButton lb = new LinkButton();
lb.ID = (++global_counter_id).ToString();
lb.Text = timeOfDay.ToShortTimeString();
lb.CommandArgument = timeOfDay.ToString();
lb.Command += new CommandEventHandler(_lnkBntRemoveSlotFromTable_Click);
newCell.Controls.Add(lb);
return newCell;
}
The method I want to be called:
public void _lnkBntRemoveSlotFromTable_Click(object sender, CommandEventArgs e)
{
//1. Make changes to the table
}
But the method is never called.
Finally got it working. A few changes made it work. It had ofcourse to do with when the table was created and how the id was created. For advice for others here is an example of when it works.. And make sure the ID of the dynamic control stays the same across page loads.
public partial class _default : System.Web.UI.Page
{
static int i = 0;
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
LinkButton lb = new LinkButton();
lb.ID = "id";
lb.Text = "Click me";
lb.CommandArgument = "argument";
lb.Command += new CommandEventHandler(method_to_call);
this.Panel.Controls.Add(lb);
}
private void method_to_call(object sender, CommandEventArgs e)
{
i++;
this.Label.Text = i.ToString();
}
protected void Page_Load(object sender, EventArgs e)
{
}
}
I have an existing drop down list(namely ddlA). On selecting a value in which, I am getting a cascading drop down list(ddlB). The requirement is, I need to create a button on the webform. By clicking the button, I would need to create drop down list dynamically of type ddlA. But here is the tricky part, I am required to present all the values in this dropdown except the selected value in the previous selection(s) of type ddlA.
Here is my code:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
List<DropDownList> DDLList = new List<DropDownList>();
Session["DDLs"] = DDLList;
}
else
{
List<DropDownList> existingDropDowns = (List<DropDownList>)Session["DDLs"];
//Add all existing DropDownLists to Panel
foreach (DropDownList dropdown in existingDropDowns)
{
Panel1.Controls.Add(dropdown);
dropdown.AutoPostBack = true;
Panel1.Controls.Add(new LiteralControl("<br/>"));
}
Session["DDLs"] = existingDropDowns;
}
}
and here is my button click event code:
protected void ddlAdditionBtn_Click(object sender, EventArgs e)
{
List<DropDownList> existingDropDowns = (List<DropDownList>)Session["DDLs"];
DropDownList newDropDown = new DropDownList();
newDropDown.ID = "DDL" + existingDropDowns.Count.ToString();
existingDropDowns.Add(newDropDown);
Panel1.Controls.Add(newDropDown);
newDropDown.AutoPostBack = true;
Panel1.Controls.Add(new LiteralControl("<br/>"));
Session["DDLs"] = existingDropDowns;
}
Below is the code to connect the existing dropdown list with the database.
protected void GetDropDowndata()
{
DataTable ddlData= lookupCache.AccessLookupData(Constants.GroupSelectionFilter.ToString());
if (ddlData != null && ddlData.Rows.Count > 0)
{
ddlData.DefaultView.Sort = "DropDownValue";
ddlData = groupsData.DefaultView.ToTable();
ddlSelectGrp.DataSource = ddlData;
ddlSelectGrp.DataTextField = "DropDownValue";//ddlSelectGrp is the existing dropdown id
ddlSelectGrp.DataValueField = "DropDownBoxID";
ddlSelectGrp.DataMember = "DropDownGroup";
ddlSelectGrp.DataBind();
ddlSelectGrp.Items.Insert(1, Constants.GroupAll.ToString());
ddlSelectGrp.SelectedIndex = 1;
btnGroupSave.Enabled = true;
btnGroupSave.CssClass = "saveButton";
}
}
But I have no idea on how to connect the dynamically generated dropdownlist with the datasource and that too without the selected value(s) in the previous dropdown list(s).
I am trying to build an app, where user can select category and according to it displays its sub categories , these sub categories are buttons, which are dynamically created.
Now, as buttons are dynamically created so I am confuse how to write code under button_click event as I dont know how many subcategories are there.
So is there any way I can execute click event of a particular button , so that I can execute certain commands?
EDITED
This is the code that i tried
Button btnDynamicButton = new Button();
private void btnclick_Click(object sender, EventArgs e)
{
label2.Text = btnDynamicButton.Text;
}
private void btnappetizer_Click(object sender, EventArgs e)
{
groupBox2.Visible =false;
DataTable dt = new DataTable();
dt = itemmasterbl.SelectallrecordFromtblItem(btnappetizer.Text);
for (int i = 0; i < dt.Rows.Count; i++)
{
string name = "Appetizer" + DynamicButtonCount;
Button btnDynamicButton1 = new Button();
btnDynamicButton1.Name = name;
btnDynamicButton1.Text = name;
btnDynamicButton1.Size =
new System.Drawing.Size(150, 30);
btnDynamicButton1.Location =
new System.Drawing.Point(180, DynamicButtonCount * 30);
btnDynamicButton1.Click +=new EventHandler(btnclick_Click);<br>
Controls.Add(btnDynamicButton1);
DynamicButtonCount++;
btnDynamicButton = btnDynamicButton1;
}
}
Once I do this it creates three buttons according to number of values in itemmaster DB under appetizer, but once I click on any of the three buttons the label displays only last buttons text,because in last line I have :
btnDynamicButton = btnDynamicButton1;
Which will last buttons infos,but rather I want which ever button I press, label should display respective text. How can I achieve this.
you can put all your logic into one handler:
System.Windows.Forms.Button b = new System.Windows.Forms.Button();
b.Click += new EventHandler(b_Click);
//finally insert the button where it needs to be inserted.
...
void b_Click(object sender, EventArgs e)
{
MessageBox.Show(((System.Windows.Forms.Button)sender).Name + " clicked");
}
To your edit:
You are storing the reference for your button(s) inside the Field btnDynamicButton. Hence it always gets overwritten with the latest button you have created. You should not reference the button by using a field. The sender parameter of the click-handler contains the button element that has been clicked. See the code above: Simple cast sender to Button and you know which button has been clicked:
private void btnclick_Click(object sender, EventArgs e)
{
Button btn = (Button)sender
label2.Text = btn.Text;
}
I got this itching problem and I cant get the code to work
How can i read the value from the TextBox when the form is posted?
Some code...
protected override void CreateChildControls() {
base.CreateChildControls();
TextBox queryBox = new TextBox();
queryBox.ID = "querybox";
queryBox.ToolTip = "Enter your query here and press submit";
Controls.Add(queryBox);
Button queryButton = new Button();
queryButton.UseSubmitBehavior = false;
queryButton.ID = "querybutton";
Controls.Add(queryButton);
if (Page.IsPostBack == true) {
try {
string query = querybox.Text;
DataGrid dataGrid = new DataGrid();
dataGrid.DataSource = Camelot.SharePointConnector.Data.Helper.ExecuteDataTable(query, connectionString);
dataGrid.DataBind();
Controls.Add(dataGrid);
} catch (Exception a) {
Controls.Add(new LiteralControl(a.Message));
} // try
} // if
} // void
I've shortened the code a bit but you see the idea, its the string query = querybox.text that wont work. I've tried with a few different variants, i.e.
TextBox querybox = (TextBox)FindControl("querybox");
string query = querybox.Text;
But no...
Any tips is appreciated!
Thanks
The problem is that your controls are not populated with values from the ViewState in CreateChildControls. I'd recommend using a click event handler on your button.
Update your button code:
Button queryButton = new Button();
queryButton.UseSubmitBehavior = false;
queryButton.ID = "querybutton";
queryButton.Text = "Query";
queryButton.Click += new EventHandler(queryButton_Click);
Controls.Add(queryButton);
Then, write the click event handler:
void queryButton_Click(object sender, EventArgs e)
{
TextBox querybox = this.FindControl("querybox") as TextBox;
try
{
string query = querybox.Text;
DataGrid dataGrid = new DataGrid();
dataGrid.DataSource = Camelot.SharePointConnector.Data.Helper.ExecuteDataTable(query, connectionString);
dataGrid.DataBind();
Controls.Add(dataGrid);
}
catch (Exception a)
{
Controls.Add(new LiteralControl(a.Message));
} // try
}
Try stepping through and looking into the Request.Form["name"] object.
What is probably happening is your Text box may not be being saved properly in the view state, but if it is a valid form object when a post back occurs it should exist within the Request.Form object, the ID may be different so you may have to do some searching.
Trikks,
I've found this which might help you.
Try looking for the text box in the load event (after checking its a postback!) rather than CreateChildControls which will separate your code out and make things a bit clearer. As Mmerrell says the id will probably get altered too, depending on the rest of the page.
You get the null reference exception because you do a
TextBox querybox = (TextBox)FindControl("querybox");
on the PAGE object.
So you're searching for page->querybox
But the textbox is in page->form1->querybox.
You need to write a recursive findcontrol, because querybox is a control in the form1 control, not a control in page.
public static Control FindControlRecursive(Control container, string name)
{
if ((container.ID != null) && (container.ID.Equals(name)))
return container;
foreach (Control ctrl in container.Controls)
{
Control foundCtrl = FindControlRecursive(ctrl, name);
if (foundCtrl != null)
return foundCtrl;
}
return null;
}
It might help to wrap the code in a !Page.IsPostBack check. Otherwise the textboxes get recreated on postback and delete any information.
if (!Page.IspostBack) {
TextBox queryBox = new TextBox();
queryBox.ID = "querybox";
queryBox.ToolTip = "Enter your query here and press submit";
Controls.Add(queryBox);
Button queryButton = new Button();
queryButton.UseSubmitBehavior = false;
queryButton.ID = "querybutton";
Controls.Add(queryButton);
} else {
try {
string query = querybox.Text;
DataGrid dataGrid = new DataGrid();
dataGrid.DataSource = Camelot.SharePointConnector.Data.Helper.ExecuteDataTable(query, connectionString);
dataGrid.DataBind();
Controls.Add(dataGrid);
} catch (Exception a) {
Controls.Add(new LiteralControl(a.Message));
} // try
} // if
Oh and don't trust the user to enter a query on your database.
Your database will crash and burn