Background
I have a table of items that the user can edit. They can navigate through the fields with the arrow keys, and the information in the current row is saved when they move to a new one. The project requires a notification be displayed to the user when the row was successfully saved, and my boss requires me to do this through Bootstrap alerts.
One alert needs to be created for each successful save, and if the user saves multiple rows in a short time they should stack inside of a panel. Because the number of alerts is unknown, I'm dynamically adding them to the page from the code-behind. Each alert is made up of a panel and a label, which is being added to a larger panel that holds all the alerts. This part I've got figured out -- the alerts show up when they're supposed to, and in the correct numbers.
The problem is that each alert is only supposed to show on the screen for a limited amount of time. This is somewhere between two and five seconds, to be determined by my boss at a later date. My idea was to start a timer for two seconds each time an alert is created, and remove the first alert from the panel when the timer finished. Because no two timers would be created at exactly the same time, this should theoretically remove each alert two seconds after it appears, stopping once the last alert is gone. Unfortunately for me, that isn't how it's working.
Instead, I get an 'index out of bounds' exception, indicating that the alert I'm trying to remove doesn't actually exist. But it does exist -- I can see it on my screen. So I'm not sure what's going wrong.
Code
Creation of Alerts
This code is inside of Page_Load, so that the alerts are still visible on postback.
if (Session["success"] != null)
{
int test = Convert.ToInt32(Session["success"]);
for(int a = 1; a <= test; a++)
{
Panel alert = new Panel();
alert.CssClass = "alert alert-success";
alert.ID = "dynamicAlert" + a;
alert.Attributes["role"] = "alert";
Label innerAlert = new Label();
innerAlert.ID = "dynamicAlertInner" + a;
innerAlert.Text = "<strong>Success!</strong> Your row was saved.";
alert.Controls.Add(innerAlert);
alertsUpdate.ContentTemplateContainer.FindControl("pnlAlerts").Controls.Add(alert);
System.Timers.Timer time = new System.Timers.Timer(2000);
time.Elapsed += removeAlert;
time.Start();
}
}
Deletion of Alerts
The removeAlert method is intended to remove the alert at index 0 from the panel contained within the update panel.
private void removeAlert(Object source, System.Timers.ElapsedEventArgs e)
{
Panel pnl = (Panel)alertsUpdate.ContentTemplateContainer.FindControl("pnlAlerts");
if(pnl != null && pnl.Controls.Count > 0)
{
pnl.Controls.RemoveAt(0);
}
}
Related
While working on a small app that pulls test cases, runs, and results from an SQL Server Database, I encountered a dilemma in my methodology for attempting to create dynamic controller names in a TableLayoutPanel in WinForms. I am creating the rows dynamically when the user chooses the particular test case, and from there the TableLayoutPanel will open another window with the test steps preloaded and two radio buttons to indicate whether or not the test passed. My issue is that when I select one of the radio buttons on the right of the step, I get the same console read every single time. I need to be able to determine which exact radio button the user has pressed so I can therefore determine what row it's in and subsequently what test either passed or failed. My main code is as follows:
FormManualTest.cs (section when adding to the TableLayoutPanel)
private void addRowToolStripMenuItem_Click(object sender, EventArgs anotherEvent)
{
tableLayoutTest.RowStyles.Clear(); // Clear row styles to ensure a clean start when adding to the TableLayoutPanel
List<RadioButton> listOfRadioControls = new List<RadioButton>(); // Create array of radio buttons
List<UserCustomStep> listOfStepControls = new List<UserCustomStep>(); // Create array of custom controls
for (int i = 0; i < 5; i++)
{
UserCustomStep step = new UserCustomStep(Counter, "Step: " + i + " Push the button to elicit a response."); // Creates new user custom step control instance
RadioButton pass = new RadioButton();
pass.Text = "Pass";
pass.AutoSize = true;
RadioButton fail = new RadioButton();
fail.Text = "Fail";
fail.AutoSize = true;
fail.Margin = new Padding(3,3,20,3); // Needed to see the fail button without having to scroll over
listOfStepControls.Add(step); // Add step to UserCustomStep array
listOfRadioControls.Add(pass); // Add radio buttons to the RadioButton array
listOfRadioControls.Add(fail);
listOfRadioControls[i * 2].CheckedChanged += (s, e) => // Subscribes the pass radio button to listen for when a user has clicked on it
{
Console.WriteLine("Pass " + i + " was clicked");
};
listOfRadioControls[(i * 2) + 1].CheckedChanged += (s, e) => // Subscribes the fail radio button to listen for when a user has clicked on it
{
Console.WriteLine("Fail " + i + " was clicked");
};
tableLayoutTest.Controls.Add(listOfStepControls[i], 0, i); // Adds CustomStep to first column
tableLayoutTest.Controls.Add(listOfRadioControls[i*2], 1, i); // Adds Pass Radio Button to second column
tableLayoutTest.Controls.Add(listOfRadioControls[(i * 2) + 1], 2, i); // Add Fail Raido Button to third column
Counter++; // Increment couter to add subsequent steps underneath the previous ones.
}
}
Screenshots of App with Console Readout:
After Test Case Has Been Clicked and Radio Button Has Been Pressed
(From clicking this I would expect the console to read "Pass 1 was clicked")
Console Read:
Click Fail Button:
(I know from this image below that since the Pass button doesn't remain clicked I'm somehow using the same controller for all 5 of them)
Console Read
So from all of these issues that I've been presented with, I know that I'm somehow using the same controller for all 5 instances regardless of the fact that I'm storing everything in a controller array and grabbing from there. The for loop will have to be converted to a for each loop later, but that still doesn't solve my issue. I believe that if I could say something like:
RadioButton (pass+id) = new RadioButton();
or something similar while looping through to dynamically create the name for the controls, then each one would be a completely separate control and I could go from there. Any help would be greatly appreciated! I come from a heavy web background so my normal skills to remedy this in JS land aren't coming in handy as of right now. Thanks again for the assistance.
The Name property is optional, you don't need to specify it and it doesn't need to be unique. You can use property Tag for your own purpose (you can assign there ID or event instance of some object).
However you can also create your own control/usercontrol which encapsulate the whole row, and you can declare your own properties exactly for your purpose.
Im programatically adding controls to one of five panels in a form every 10 seconds. When all 5 panels are filled I clean the first one and add my new control in there and so on.
Now everytime I add a new control my form gets focused and the application I'm working is loses focus.
How can I prevent my form from beeing focused?
//EDIT
I found out that the last focused control (in my case a button) gets the focus upon the new created control, but I still dont know how to give my previous application the focus again
Code:
System.Threading.Timer timer = new System.Threading.Timer(x => {
if (!startStopBool) return;
if (controlIdx == 5) controlIdx = 0;
{
if (controlArray[controlIdx] != null)
{
DisposeControl(controlArray[controlIdx]);
}
controlArray[controlIdx] = AddControl(controlIdx);
controlIdx++;
}
}, null, 0, 10000);
after adding the control in the AddControl-function (a WebBrowser) the last used control from my form (the button) steals the focus
I have a class
public class LabelContainer:WebControl
{
private Label myLable= new Label();
private TextBox t = new TextBox();
public void FlashControl()
{
myLable.Text = 15;
If (Int16.Parse(myLable.text)>10)
{
myLable.Visible =! myLable.Visible
}
else
{
_Label.Visible
}
}
}
And i am 'new'ing it up on default page on every tick of master page timer. Master page has a timer and has a tick event. Master page timer is in update panel with AsyncPostBackTrigger and ContentTemplate (it just display time on master and all pages, i am not sure its relevant).
var label = new LabelContainer();
label.FlashControl();
On every tick the 'new'ing up happens but Control Doesn't Blink. It either stays visible if text is < 10 or stays invisible if text > 10. Is there any way i can make this label to blink if it meets certain criteria? Or any other substitute for this (if its without jquery or java script would be great)
Thanks in Advance
I am working on creating buttons that are created dynamically based the results of a SQL Query:
private void createPagingButtons(DateTime firstDayofWeek, DateTime lastDayofWeek)
{
int i = 1;
SqlDataReader returnedQuery = getDefaultUser(firstDayofWeek, lastDayofWeek);
while (returnedQuery.Read())
{
string buttonName = returnedQuery["Person"].ToString();
System.Diagnostics.Debug.WriteLine(buttonName);
Button btn = new Button();
btn.ID = i.ToString();
btn.Click += new EventHandler(btn_Click);
btn.Text = buttonName;
pagingPanel.Controls.Add(btn);
i++;
}
}
The way I am trying to assign unique button ID's is by assigning them a number that is incremented each time the while loop iterates:
btn.ID = i.ToString();
But it's not working and I am getting an error:
Multiple controls with the same ID '1' were found. FindControl requires that controls have unique IDs.
WHy is this happening and how can I fix it?
The only way this could occur is if this method were executed more than one time or if these buttons are somehow persisted during the load and then you call it again. However, dynamic controls are for all intents and purposes not persisted and must be recreated on each post back to be useful.
Thus my conclusion, you're calling it more than once.
As other users said, this error will be thrown if the function is called more than once. Your function will re-start at one each time it is called. Which will duplicate the IDs.
Assuming this is actually the desired behavior, that your function can be called multiple times and will create new buttons each time. Making your int i = 1; a class level variable would resolve this.
Replace i++ with ++i.. This should solve your issue..
How can I create progress update control programmatically in a c# non visual web part in Sharepoint?
I am using c# and the goal is to creates a text of "Loading..." inside the ProgressUpdate control that becomes visible while the update panel is loading more content and then disappears when content is loaded. If anyone can help that would be awesome. I tried the following, but no luck. A button triggers the update panel and the update works well, but when I try to add an update progress it gets added into the page, but it never appears when I click my button that triggers the update.
UpdatePanel up = new UpdatePanel();
up.UpdateMode = UpdatePanelUpdateMode.Always;
up.ID = "Panel1";
UpdateProgress upp1 = new UpdateProgress();
upp1.AssociatedUpdatePanelID = up.ID.ToString();
upp1.ID = "UpdateProgress1";
upp1.Controls.Add(new LiteralControl("<p>Loading...</p>"));
Controls.Add(upp1);
Alright so here is what I have found. If you make an Update Progress control outside an Update Panel, then it will fail to be able to listen to the trigger on the update panel when it fires. More can be read about that at the link below.
http://www.mostlydevelopers.com/blog/post/2008/08/23/Show-UpdateProgress-when-using-an-UpdatePanel-with-Triggers.aspx
So since I'm doing it this way, I had to use a javascript work around. I had to use the getInstance() method of the PageRequestManager object to get the instance of the PageRequestManager class. I then added the functions for the asynchronous request when it is initialized and ends. This will allow us to show our UpdateProgress control when an Asynchronous call begins and ends. (See Javascript Below)
//Function for postbackUpdateProgress
var prm = Sys.WebForms.PageRequestManager.getInstance();
var postBackElement;
function CancelAsyncPostBack() {
if (prm.get_isInAsyncPostBack()) {
prm.abortPostBack();
}
}
prm.add_initializeRequest(InitializeRequest);
prm.add_endRequest(EndRequest);
function InitializeRequest(sender, args) {
if (prm.get_isInAsyncPostBack()) {
args.set_cancel(true);
}
//Get the element that asynchronous postback
postBackElement = args.get_postBackElement();
//check to see if any of the following controls activate sender request.
//search is used to search for the ID name in the string that sharepoint spits out
// as the ID.
var controlA = postBackElement.id.search("DropDownListType");
var controlB = postBackElement.id.search("UserProfileDropList");
var controlC = postBackElement.id.search("MoreNewsLinkButton");
var controlD = postBackElement.id.search("PreviousNewsLinkButton");
if (controlA != -1 || controlB != -1 || controlC != -1 || controlD != -1) {
$('*[id*=Panel1]:visible').hide();
//show UpdateProgress
$('*[id*=UpdateProgress1]').show();
}
}
//After async postback complete, then show panel again and hide UpdateProgress
function EndRequest(sender, args) {
$('*[id*=Panel1]').show();//use wild card in jquery to find Panel1 ID
$('*[id*=UpdateProgress1]:visible').hide();
}
Please note that I had to do a search() for the ID name because sharepoint puts a bunch of text before your ID name and javascript would otherwise not be able to find it by the text literal of the ID alone. A wild card approach with jquery is used to find the panel by using:
$('[id=Panel1]').show();//use wild card in jquery to find Panel1 ID
to show it.
and
$('[id=Panel1]:visible').hide();
to hide the update panel when the async call is initialized. You don't have to hide the update panel, but my particular implementation looks more aesthetically pleasing if I do.