I usually figure things out but this has me beat.
I have an array of listboxes on a form and a submit button. The user can pick items from any listbox then click the submit button to choose the confirm the item, but what needs to happen is that if they select something from listbox 1 then change their mind and select something from listbox 2, the item selected in listbox 1 should become unselected.
I can code that in to the eventhandlers but the problem is as soon as I change a value in another listbox programatically it fires another event. I can't seem to logic my way out of it.
Any ideas would be great otherwise I guess I will just have to put multiple submit buttons.
EDIT:
I figured out what I think is quite an obvious and simple solution in the end. I made use of the focused property to distinguish whether the user or the program was making changes. Works for both mouse and keyboard selections.
Thanks for the suggestions...
for (int i = 0; i < treatments.Length; i = i + 1)
{
this.Controls.Add(ListBoxes[i]);
this.Controls.Add(Labels[i]);
this.Controls.Add(Spinners[i]);
Labels[i].Top = vPosition - 20;
Labels[i].Left = hPosition;
Labels[i].Width = 600;
ListBoxes[i].Left = hPosition;
ListBoxes[i].Top = vPosition;
ListBoxes[i].Width = 600;
Spinners[i].Top = vPosition + ListBoxes[i].Height;
Spinners[i].Left = hPosition + ListBoxes[i].Width - 60;
Spinners[i].Width = 40;
for (int d = 25; d > 0; d = d - 1) { Spinners[i].Items.Add((d).ToString()); }
Spinners[i].SelectedIndex = 24;
//EVENT HANDLER CODE that is executed if any selectetindexchange in any LIstbox in array
ListBoxes[i].SelectedIndexChanged += (sender, e) =>
{
for (int s = 0; s < i; s = s + 1)
{
//FIND WHICH LBs[s] IS THE SENDING LISTBOX
if (ListBoxes[s] == sender && ListBoxes[s].Focused == true)
{
string msg = "sender is ListBox " + s.ToString() + "\nFocus is" + ListBoxes[s].Focused.ToString();
// MessageBox.Show(msg);
}
else if(ListBoxes[s].Focused==false)
{
ListBoxes[s].SelectedIndex = -1;
}
}
}; //end of event handler
}
I generally solve this kind of problem with a flag that lets me know that I am changing things, so my event handlers can check the flag and not take action in that case.
private int codeChangingCount = 0;
private void combobox1_SelectedIndexChanged(object sender, EventArgs e) {
codeChangingCount++;
try {
combobox2.SelectedIndex = someNewValue;
} finally {
codeChangingCount--;
}
}
private void combobox2_SelectedIndexChanged(object sender, EventArgs e) {
if (codeChangingCount == 0) {
//I know this is changing because of the user did something, not my code above
}
}
You can do this with a simple bool instead of an int, but I like the counter approach so that I can keep incrementing codeChangingCount in nested calls and not accidentally reset it. In my production code, I have a class dedicated to this kind of flagging, and it (mis)uses IDisposable to decrement, so I can just wrap my calls in a using block, but the above snippet is simpler for illustration.
Check if Focused ListBox == ListBox2 and SelectedIndex > -1 then deselect Index[0]
if (ListBoxes[s] == sender && ListBoxes[s].Focused == true)
{
if(s == 1 && ListBoxes[s].SelectedIndex > -1) //assuming 1 is listbox2
{
ListBoxes[0].SelectedIndex = -1; // Deselect ListBox1
}
string msg = "sender is ListBox " + s.ToString() + "\nFocus is" + ListBoxes[s].Focused.ToString();
}
Related
I'm having quite a strange issue where my generated control will not fire its' SelectedIndexChanged event on the first click, but will dutifully work after that.
The code is as follows:
//Generate list
ddl.Items.Add(new ListItem(" ", " "));
for(int i =1 ; i < 13 ; i ++)
{
ddl.Items.Add(new ListItem(i.ToString(),i.ToString()));
}
//ddl.SelectedIndex = -1;
tc2.Controls.Add(ddl);
tr.Cells.Add(tc2);
//Keep position after postback
for (int i = 1; i < 13; i++)
{
if (i.ToString() == sNoOfPreviousMonths )
{
ddl.SelectedIndex = i;
}
}
And the event:
void ddlNoOfPreviousMonths_SelectedIndexChanged(object obj, EventArgs e)
{
DropDownList x = obj as DropDownList;
sNoOfPreviousMonths = x.SelectedValue;
}
I found out the answer, turns out that on the first click the control's ID is different, and gets changed on the second click. It's explained better here
i think u dont use Autopostback for dropdownlist. u need set to be true value
I am creating a few checkboxes when I open a form with the following code:
private void OpenFolder_Load(object sender, EventArgs e)
{
int i = 0;
foreach (string file in filesToOpen)
{
Label lbl = new Label();
lbl.Text = Path.GetFileNameWithoutExtension(file);
lbl.Width = 200;
lbl.Height = 25;
lbl.AutoEllipsis = true;
lbl.Location = new System.Drawing.Point(10, 40 + 25 * i);
this.Controls.Add(lbl);
string checkName = "check" + i;
CheckBox check = new CheckBox();
check.Checked = true;
check.AccessibleName = checkName;
check.Location = new System.Drawing.Point(340, 40 + 25 * i);
check.CheckedChanged +=new EventHandler(check_CheckedChanged);
this.Controls.Add(check);
CheckBoxes.Add(check);
i++;
}
and I am trying to check the state of the checkboxes everytime one changes to toggle my OK button (the user can validate only if there are a certain number of the checkboxes checked)
here is the code I use, but it fails as I am not able to target the checkboxes:
private void check_CheckedChanged(Object sender, EventArgs e)
{
for (int i = 0; i < filesToOpen.Count(); i++)
{
string tbarName = "tbar" + i;
string checkName = "check" + i;
CheckBox ckb = this.Controls.OfType<CheckBox>()
.Where(c => c.AccessibleName.Equals(checkName)) as CheckBox;
TrackBar tkb = this.Controls.OfType<TrackBar>()
.Where(t => t.AccessibleName.Equals(tbarName)) as TrackBar;
//TrackBar tkb = this.Controls.Find(tbarName, false).First() as TrackBar;
//CheckBox ckb = this.Controls.Find(checkName, false).First() as CheckBox;
if (ckb.Checked == true)
{
//do stuff
}
}
}
what am I doing wrong/really wrong?
Given that you add the checkboxes to your own list:
CheckBoxes.Add(check);
it would be simpler to loop over that rather than trying to find the control associated with the file:
foreach (var checkBox in CheckBoxes)
{
if (checkbox.Checked)
{
// Do stuff...
}
}
However, you shouldn't need to use a separate list. This line is wrong:
CheckBox ckb = this.Controls.OfType<CheckBox>()
.Where(c => c.AccessibleName.Equals(checkName)) as CheckBox;
Where returns a IEnumerable<CheckBox> but you are trying to cast it directly to a CheckBox which will return null. What you should have is:
CheckBox ckb = this.Controls.OfType<CheckBox>()
.Where(c => c.AccessibleName.Equals(checkName)).First();
You will still need to check to see if ckb is null (just in case there is nothing on the list) but this should return you the control you are looking for.
Check the type of "this" and then check its Controls collection - your checkboxes are probably a few iterations down the tree.
You'd need some kind of recursive find controls function such as the one found in this article
Iterating over all the checkboxes with every check is not required and is readlly hard processing work. Instead when creating you always know in what state you've created those - so just keep the count of "Checked" checkboxes. When a checkbox being checked increment the count, and when one unchecked - take out 1 from the count. And later have a check: "if (count == requiredCount) {//Logic here}"
So the code will look like:
private int checkedCount;
private void check_CheckedChanged(Object sender, EventArgs e)
{
this.checkedCount += (sender as CheckBox).Checked?1:-1;
if(this.checkedCount == requiredCount)
{
//do stuff
}
}
Good luck with development.
I think it's obvious what I'm trying to do, but if you don't understand, please ask.
if (listBox1.SelectedIndex == 1 && 2)
{
label1.Text = "Sometext";
}
SelectedIndices is what you want if you have enabled multi-select. You can also check the size of the SelectedItems property.
The documentation for ListBox.SelectedIndex states:
For a standard ListBox, you can use this property to determine the index of the item that is selected in the ListBox. If the SelectionMode property of the ListBox is set to either SelectionMode.MultiSimple or SelectionMode.MultiExtended (which indicates a multiple-selection ListBox) and multiple items are selected in the list, this property can return the index to any selected item.
Try this
if( listBox1.SelectedItems.Count > 1 )
{
// multiple items are selected
}
if (listBox1.SelectedIndices.Count > 1) // I'd use to group all of your multi-selection cases
{
if (listBox1.SelectedIndices.Contains(1) && listBox1.SelectedIndices.Contains(2))
{
label1.Text = "Sometext";
}
}
Keep in mind that the control is 0 based so if you're trying to select the first two options, you'll want to check for 0 (item 1) and 1 (item 2).
edit: modified to handle the requirement listed in comments. Note, there's probably a better way and there may even be a method for this built in (never used the multi-selection list box). But I built a function to handle so you don't have to do it for every scenario.
The function that does the work:
private bool CasesFunction(ListBox lbItem, List<int> validIndices)
{
for (int index = 0; index < lbItem.Items.Count; index++)
{
if (lbItem.SelectedIndices.Contains(index) && !validIndices.Contains(index))
return false;
}
return true;
}
And how I used it:
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (listBox1.SelectedIndices.Count > 1)
{
List<int> MyCase = new List<int> { 0, 1 };
if (CasesFunction(listBox1, MyCase))
{
label1.Text = "Sometext";
return;
}
else
label1.Text = "";
MyCase = new List<int> { 1, 2 }; // can do other checks
if (CasesFunction(listBox1, MyCase))
{
label1.Text = "Sometext 2";
return;
}
else
label1.Text = "";
}
else
label1.Text = listBox1.SelectedIndex.ToString();
}
I have an application which has to monitor 211 rods, and every 5 seconds it will update 2 ListBox controls, each one containing either the inserted rods or the removed ones. When I manually use the button for inserting/removing rods the code executes perfectly and the ListBoxes update properly. When I use the global button which inserts all 211 one of the ListBox controls stops working properly.
The code for ListBox update
bool IClear = true, RClear = true;
for (int foo = 0; foo < Rods.Count; foo++)
{
if (Rods[foo].State == RodState.Inserted)
{
UpdateRodList update = new UpdateRodList(UpdateIRodUI);
if (IClear)
{
InsertedRods.Dispatcher.BeginInvoke(update, System.Windows.Threading.DispatcherPriority.Normal, foo, true);
IClear = false;
}
else
{
InsertedRods.Dispatcher.BeginInvoke(update, System.Windows.Threading.DispatcherPriority.Normal, foo, false);
}
}
if (Rods[foo].State == RodState.Removed)
{
UpdateRodList update = new UpdateRodList(UpdateRRodUI);
if (RClear)
{
RemovedRods.Dispatcher.BeginInvoke(update, System.Windows.Threading.DispatcherPriority.Normal, foo, true);
RClear = false;
}
else
{
RemovedRods.Dispatcher.BeginInvoke(update, System.Windows.Threading.DispatcherPriority.Normal, foo, false);
}
}
}
The code for the insert button (the remove one is similar)
Int32[] RodsID = null;
bool bParsed = false;
if (RemovingRods_.Text.Contains("*"))
{
RodsID = new Int32[211];
for (int i = 0; i < 211; i++)
{
RodsID[i] = i;
}
RemovingRods_.Text = "";
bParsed = true;
}
if (RemovingRods_.Text.Contains("-"))
{
string stext = RemovingRods_.Text;
Int32 a = Int32.Parse(RemovingRods_.Text.Substring(0, RemovingRods_.Text.IndexOf("-")));
Int32 b = Int32.Parse(RemovingRods_.Text.Substring(RemovingRods_.Text.IndexOf("-") + 1));
RodsID = new Int32[b - a];
for (int i = 0; i < b - a; i++)
{
RodsID[i] = i + a;
}
RemovingRods_.Text = "";
bParsed = true;
}
if (!bParsed)
{
string[] RodsID_;
char[] split = { ' ' };
RodsID_ = RemovingRods_.Text.Split(split);
RemovingRods_.Text = "";
RodsID = new Int32[RodsID_.Length];
for (int i = 0; i < RodsID_.Length; i++)
{
RodsID[i] = Int32.Parse(RodsID_[i]);
}
}
foreach (int numb in RodsID)
{
if (Rods[numb].Type == "Control Rod")
{
ControlRod Rod = new ControlRod();
Rod.Number = numb;
Rod.RodState = RodState.Changing;
RemovingCRods.Add(Rod);
}
if (Rods[numb].Type == "Shortened Control Rod")
{
ShortenedControlRod Rod = new ShortenedControlRod();
Rod.Number = numb;
Rod.RodState = RodState.Changing;
RemovingSRods.Add(Rod);
}
if (Rods[numb].Type == "Automated Control Rod")
{
// Automated Rods -- NO MANUAL CONTROL
}
}
And the global button code
try
{
Int32[] RodsID = null;
string text = "0-211";
RodsID = new Int32[211];
for (int i = 0; i < 211; i++)
{
RodsID[i] = i;
}
foreach (int numb in RodsID)
{
if (Rods[numb].Type == "Control Rod")
{
ControlRod Rod = new ControlRod();
Rod.Number = numb;
Rod.RodState = RodState.Changing;
InsertingCRods.Add(Rod);
}
if (Rods[numb].Type == "Shortened Control Rod")
{
ShortenedControlRod Rod = new ShortenedControlRod();
Rod.Number = numb;
Rod.RodState = RodState.Changing;
InsertingSRods.Add(Rod);
}
if (Rods[numb].Type == "Automated Control Rod")
{
AutomatedControlRod Rod = new AutomatedControlRod();
Rod.Number = numb;
Rod.RodState = RodState.Changing;
InsertingARods.Add(Rod);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
What happens is when I press the global one, the Removed Rods ListBox will have all the rods as it should, and the Inserted Rods ListBox will contain the rods that were inserted before I pressed the button. It's as if when I pressed this button, this control doesn't update. P.S. If I remove rods manually using the button or insert it works perfectly.
As for the code requested by Marko:
private void UpdateIRodUI(Int32 foo, Boolean clear)
{
if (clear)
{
InsertedRods.Items.Clear();
}
InsertedRods.Items.Add(Rods[foo].Number + " : " + Rods[foo].Type + " (" + foo.ToString() + ")");
}
private void UpdateRRodUI(Int32 foo, Boolean clear)
{
if (clear)
{
RemovedRods.Items.Clear();
}
RemovedRods.Items.Add(Rods[foo].Number + " : " + Rods[foo].Type + " (" + foo.ToString() + ")");
}
Update: I have put the update ListBox code in a seperate function and took Marko's advice and also put in a function the InsertRods. Everything works fine now, but it seems that after I press the "emergency" button the InsertedRods ListBox updates and works just fine but RemovedRods just stops updating, unless I do it manually (it's supposed to update every 5 seconds through a Tick event). I even tried inserting all the rods, updating the ListBoxes and the clearing the "faulty" ListBox and still nothing, same result.
I just took a quick glance of your posted code without focusing very deeply on it and a couple of questions popped into mind:
1) You posted your code for ListBox update, but it's unclear from the other two code pieces that where do you call the ListBox update method?
2) The code that you posted for "insert button" looks more like the code from the "remove button", because of Removing_Rods.Add()... But why do you duplicate your insert/remove button code in your global button code? Why not have an insert method, that both the insert button and global (insert) button call? And the same for remove. If you need to slightly alter the code based on whether the caller is the insert button or the global button, you can pass in a variable and check it inside the insert method.
3) Have you tried debugging your code? As in whether the listbox update method is called when the global button code is executed...
I've got a formview whose load event just decided to stop working. I did some debugging and noticed that it was reaching the code, but for whatever reason, the attributes that I am adding in the load event are no longer displaying on the screen. It's as if something is happening after the formview's load event that is reloading it without any of my extra attributes. The only modification that I have done before it stopped working is that I added a session variable in the page before it. That should not cause such a drastic change.
Here is my code:
protected void FormView1_Load(object sender, EventArgs e)
{
RadioButton rbinjury = (RadioButton)FormView1.FindControl("rbinjury");
RadioButton rbproperty = (RadioButton)FormView1.FindControl("rbproperty");
RadioButton rbboth = (RadioButton)FormView1.FindControl("rbboth");
RadioButton rbyes = (RadioButton)FormView1.FindControl("rbyes");
RadioButton rbno = (RadioButton)FormView1.FindControl("rbno");
RadioButton rbyes2 = (RadioButton)FormView1.FindControl("rbyes2");
RadioButton rbno2 = (RadioButton)FormView1.FindControl("rbno2");
RadioButton rbam = (RadioButton)FormView1.FindControl("rbam");
RadioButton rbpm = (RadioButton)FormView1.FindControl("rbpm");
TextBox txtdate = (TextBox)FormView1.FindControl("txtdate");
DropDownList ddlhour = (DropDownList)FormView1.FindControl("ddlhour");
DropDownList ddltime = (DropDownList)FormView1.FindControl("ddltime");
if (FormView1.CurrentMode == FormViewMode.Insert || FormView1.CurrentMode == FormViewMode.Edit)
{
txtdate.Attributes.Add("onfocus", "unfocus();");
locList.Attributes.Add("onChange", "postBack();");
ddlhour.Items.Insert(0, new ListItem("Hour", "0"));
ddlhour.Items.Insert(1, new ListItem("12", "12"));
ddltime.Items.Insert(0, new ListItem("Minute", "0"));
for (int i = 1; i < 12; i++)
{
String hour = Convert.ToString(i);
ddlhour.Items.Add(new ListItem(hour, hour));
}
for (int i = 0; i < 61; i++)
{
String time = "";
if (i < 10)
{
time = ":0" + Convert.ToString(i);
}
else
{
time = ":" + Convert.ToString(i);
}
ddltime.Items.Add(new ListItem(time, time));
}
//-----------------------------------------handle radio buttons----------------------------------------------------------------
rbinjury.Attributes.Add("Onclick", "radio('rbinjury','result');");
rbproperty.Attributes.Add("Onclick", "radio('rbproperty','result');");
rbboth.Attributes.Add("Onclick", "radio('rbboth','result');");
rbyes.Attributes.Add("Onclick", "radio('rbyes','inj');");
rbno.Attributes.Add("Onclick", "radio('rbno','inj');");
rbyes2.Attributes.Add("Onclick", "radio('rbyes2','dmg');");
rbno2.Attributes.Add("Onclick", "radio('rbno2','dmg');");
rbam.Attributes.Add("Onclick", "radio('rbam','time');");
rbpm.Attributes.Add("Onclick", "radio('rbpm','time');");
}}
Any idea what would cause the load event to stop working? If I place this same code in the page's save state complete event, it does work, but I should not have to...
you need to use formview Databound event instead of formview load event to set values, try
using this
protected void frm_DataBound(object sender, EventArgs e)
{
if (frm.CurrentMode == FormViewMode.Edit)
{
TextBox txtdate = (TextBox)frm.FindControl("txtdate");
txtdate.Attributes.Add("", "");
}
}
Also check these threads.
ASP.NET Can not Change Visibility of a Formview control
FormView.FindControl(): object reference error