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
Related
I made a simple button, but when i click outside of win form my button getting a black border. By the way i set BorderSize to "0" and it works great while i clicking inside of my form.
this.button.FlatAppearance.BorderSize = 0;
That's how it looks like.
it seems a focus problem. Try to reset the focus when the cursor leave the control.
Add these lines of code to your forms load event.
btn.FlatStyle = FlatStyle.Flat;//You can also use the popup flat style
btn.FlatAppearance.BorderColor = btn.Parent.BackColor;
btn.FlatAppearance.BorderSize = 0;
One simple workaround is to set the FlatAppearance.BorderColor of the Button to its Parent.BackColor:
this.button1.FlatAppearance.BorderColor = this.button1.Parent.BackColor;
You could set this Property subscribing to the ParentChanged event (or overriding OnParentChanged, if it's a Custom Control) if the Control can be assigned to another parent at some point.
You can also perform the same operation in batch, using the HandleCreated event and have all the Buttons (with FlatStyle = FlatStyle.Flat) subscribe to the event in the Form's constructor:
public Form1()
{
InitializeComponent();
foreach (Button button in this.Controls.OfType<Button>().Where(btn => btn.FlatStyle == FlatStyle.Flat))
{
button.HandleCreated += (s, e) => {
button.FlatAppearance.BorderColor = button.Parent.BackColor;
};
}
}
I have a Panel that has AutoScroll = true.
In that Panel is a series of TextBoxes. I should note that the TextBoxes aren't on the panel directly but are nested several levels (about 4-5).
Now, the scrolling with my mouse wheel works only if the panel has focus, naturally. I can use Focus() within mouseEnter event to make sure the panel has focus.
However, the TextBoxes I mentioned earlier rely heavily on focus. Only the user should be able to remove focus from the TextBox by clicking somewhere else.
The TextBoxes are created dynamically and would make for a very messy code to keep an array of them, or any type of reference to check if they have focus. Not to mention that there could be a lot of them.
How do I give the focus to the Panel, but only if none of the TextBoxes is focused?
You don't need to keep an array of the dynamically created Textboxes, you can get the array using:
bool anyTextBoxFocused = false;
foreach (Control x in this.Controls)
{
if (x is TextBox && x.Focused)
{
anyTextBoxFocused = true;
break;
}
}
if (!anyTextBoxFocused)
{
//give focus to your panel
}
Edit
Based on How to get ALL child controls of a Windows Forms form of a specific type (Button/Textbox)?, even nested controls can be obtained using:
public IEnumerable<Control> GetAll(Control control,Type type)
{
var controls = control.Controls.Cast<Control>();
return controls.SelectMany(ctrl => GetAll(ctrl,type))
.Concat(controls)
.Where(c => c.GetType() == type);
}
then use it with:
var c = GetAll(this,typeof(TextBox));
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);
}
}
I have a custom Tabs Control I created. It works as a coloured Label for the tab itself and as a Panel to hold the contents. My application reads UI parameters from config files. Take this line as an example from the controls config:
RTFBOX=(ID - rtf1) (BOUNDS - 0,0,100,100) (MULTILINE - enable) (FILE - email_rules.rtf)
This line tells the application to create an instance of my custom RichTextBoxPlus class and the important thing to take from this is that it is set up to read rich text from the FILE parameter. If I don't add this RichTextBoxPlus to another Control it shows it's rich text formatting absolutely fine.
I have another config that reads actions at runtime, this can be simple stuff like telling a Button created with the controls config that when it is clicked, it should fire off an email using content from a TextBox control. I have an action that pairs controls to each tab in the Tabs custom control. For example:
ADDTOTABS=(OBJECT - tabsControl1) (CONTROLS - panel1, panel2)
This finds tabsControl1 and adds panel1 to the 1st tab and panel2 to the 2nd tab. In this example, Panels are being added to each tab instead of individual controls as the Panels could hold multiple controls, handled at runtime through the ADDTOPANEL action.
ADDTOPANEL=(OBJECT - rtf1) (TARGET - panel1) (TRIGGER - onload)
So the rtf1 instance of RichTextBoxPlus is added to panel1 which is then added to the respective Panel of the Tabs control's 1st tab.
What I have found is rtf1 displays with rich text formatting absolutely fine if added to panel1 but not adding panel1 to Tabs.
The ADDTOTABS action executes this method:
private void TabContents_Action(Tabs tabpanel, string[] ctrls)
{
string[] tabs = tabpanel.GetTabNames();
for(int i = 0; i < tabs.Length; i++)
{
Control control = this.Controls.Find(ctrls[i], true).FirstOrDefault();
tabpanel.SetTaggedObject(control, tabs[i]);
}
tabpanel.SetTabActive(tabs[0]);
}
The SetTaggedObject method of the Tabs class finds the Panel control that corresponds with the tab name provided:
public void SetTaggedObject(Control ctrl, string tab)
{
Control container = this.Controls.Find(tab, false).FirstOrDefault();
container.Controls.Add(ctrl);
}
Doesn't seem to be anything untoward about this method.
The SetTabActive method of the Tabs class has a little more bulk. This handles changing the appearance of all tabs so that inactive tabs look different to the active tab. It is also hides and shows the panels for each tab based on whether the tab is active.
public void SetTabActive(string tab)
{
LabelPlus activeTab = this.tabs.Find(x => x.Name.Equals(tab));
List<LabelPlus> inactiveTabs = new List<LabelPlus>(this.tabs.FindAll(x => !x.Name.Equals(tab)));
activeTab.BackColor = this.ActiveColor;
activeTab.ForeColor = this.ActiveForeColor;
string panelName = tab.Remove(tab.Length - this.tabSuffix.Length);
Panel activeTabPanel = (Panel)this.Controls.Find(panelName, true).FirstOrDefault();
activeTabPanel.Bounds = new Rectangle(
new Point(this.tabStart, this.originalLocation.Y + this.TabTotalHeight), this.Size);
ControlCollection activeTabCtrls = activeTabPanel.Controls;
foreach(LabelPlus inactiveTab in inactiveTabs)
{
inactiveTab.BackColor = this.InactiveColor;
inactiveTab.ForeColor = this.InactiveForeColor;
string inactivePanelName = inactiveTab.Name.Remove(inactiveTab.Name.Length - this.tabSuffix.Length);
Panel inactiveTabPanel = (Panel)this.Controls.Find(inactivePanelName, true).FirstOrDefault();//
inactiveTabPanel.Bounds = new Rectangle(
new Point(this.tabStart, this.originalLocation.Y + this.TabTotalHeight), this.Size);
ControlCollection inactiveTabControls = inactiveTabPanel.Controls
foreach (Control ctrl in inactiveTabControls) { ctrl.Location = new Point(0, ctrl.Location.Y); ctrl.Hide(); }
}
foreach (Control ctrl in activeTabCtrls)
{ ctrl.Location = new Point(0, ctrl.Location.Y); ctrl.Show(); }
}
Not sure but I'd say the issue must be in this method. Any thoughts?
I have a TabControl that starts with three TabPages in it. On the first tab there is a NumericUpDown (spinner) which displays the number of tabs and allows a user to add up to 10 extra tabs. Once they add more than about 5 or 6 it goes beyond the width of the form and the rest of the tabs are accessible by a couple of left/right arrows at the top. When going all the way to the right and then using the spinner to go back down to 0 (removing all the extra tabs and leave the starting three) it removes all tabs from the top of the pane and only by setting the spinner back to 1 does it refresh and display all 4 (3 from the start plus the 1 from the spinner).
I have tried several commbinations of
Application.DoEvents()
this.Refresh()
this.Invalidate()
this.Update()
but nothing seems to work. can anybody suggest a reason why it is not updating/refreshing?
public partial class Form1 : Form
{
TabPage[] tabs;
public Form1()
{
InitializeComponent();
tabs = new TabPage[tabControl1.Controls.Count];
tabs[0] = tabPage1;
}
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
int numTabs = tabControl1.Controls.Count;
decimal spinnerValue = numericUpDown1.Value;
if (numTabs < spinnerValue) //add a tab
{
TabPage[] newTabs = new TabPage[(int)spinnerValue];
for (int i = 0; i < numTabs; i++)
{
newTabs[i] = tabs[i];
}
TabPage tab = new TabPage("Tab " + numTabs);
newTabs[(int)spinnerValue-1] = tab;
tabControl1.Controls.Add(tab);
tabs = newTabs;
}
else //remove a tab
{
TabPage[] newTabs = new TabPage[(int)spinnerValue];
for (int i = 0; i < spinnerValue; i++)
{
newTabs[i] = tabs[i];
}
tabControl1.Controls.Remove(tabs[(int)spinnerValue]);
tabs = newTabs;
}
}
}
Without seeing any code or knowing what type of project this is winforms, WPF, ASP.NET etc..
it's hard to give a definite answer, I am going to assume that this is WinForms
I'm not sure if you can. The following is a quote from MSDN:
"Controls contained in a TabPage are not created until the tab page is shown, and any data bindings in these controls are not activated until the tab page is shown."
However, instead of having the update code get the values from the controls directly, maybe you could create a class that could hold the Data you use to populate the controls and then when the update code is called it asks the class for the value and the class checks if the control is loaded and otherwise it gets the value from the Data instead.