Docking an Encapsulated Control - c#

I have an encapsulated control in a derived TabPage, and I am having trouble docking it to the form MainForm that contains the derived TabPage.
I've added the TabPage and the control correctly, and they are showing up on MainForm. However, the control is not correctly docked (style: fill). You can verify this by resizing the form.
I've set the property _control.Dock = System.Windows.Forms.DockStyle.Fill and _control.Anchor = Left | Right | Top | Bottom in the derived TabPage's constructor.
Below is the sample of the code:
public class DerivedTab : TabPage {
public DerivedTab(){
...
_control= new BrightIdeasSoftware.TreeListView();
this.Controls.Add(this._control);
_control.Anchor = System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right | System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom;
_control.Dock = System.Windows.Forms.DockStyle.Fill;
...
}
}
In the MainForm, this is the function that creates the derived tab in run-time:
private DerivedTab CreateTab(string name)
{
DerivedTab tab = new DerivedTab(this, name);
tab.SuspendLayout();
MainTab.Controls.Add(tab);
return tab;
}
Anyways, I generated this code using Visual Studio Designer, and the control docks correctly. I, then, created a class for the tabpage (since I will need many and varying number of these tabs) and copied everything relates to tabpage to the CreateTab function. I moved anything relates to the the property of the tabpage into its constructor. I encapsulated the control in the derived TabPage and moved everything related to the control in the derived tabpage.
So, what I am missing? Is it possible to dock the encapsulated control without implementing an eventhandler function?

I found the solution to my own problem. ResumeLayout has to be called after the TabControl adds the TabPage for the TabPage to dock properly.
private DerivedTab CreateTab(string name)
{
DerivedTab tab = new DerivedTab(this, name);
tab.SuspendLayout();
MainTab.Controls.Add(tab);
tab.ResumeLayout();
return tab;
}

Related

Basic Layout with WindowsForms

How do I create a simple form that has a MenuStrip at the top and a TabControl filling all of the remaining space?
If I go with DockStyle.Top/DockStyke.Fill tabControl fills whole form regardless of MenuStrip:
public MainWindow()
{
initializeComponent();
}
private void initializeComponent()
{
MenuStrip mainMenu = new MenuStrip();
mainMenu.Dock = DockStyle.Top;
TabControl tabs = new TabControl();
tabs.Dock = DockStyle.Fill;
TabPage test = new TabPage("test");
tabs.Controls.Add(test);
Controls.Add(mainMenu);
Controls.Add(tabs);
}
You should change the z-order of mainMenu or tabs. For example you can call:
mainMenu.SendToBack();
//Or
//tabs.BringToFront();
After adding controls to the controls collection.
Another approach through designer, without writing code manually, so your changes will affect design time too
Use Document outline tab and arrange control's hierarchy with your requirements
View -> Other Windows -> Document outline or CTRL+ALT+T

RichTextBox showing with plain text when added to Panel

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?

Place form1(No border style) inside of form2(Normal border style) [duplicate]

This question already has an answer here:
Add Form to a UserControl - is this possible?
(1 answer)
Closed 8 years ago.
I would like to know if it is possible to show/place a form1 INSIDE form2.
So that form1 is stuck inside form2.
Any help will be appreciated. thanks in advance.
Yes. The word you're looking for is MDI or Multiple Document Interface.
Just set form2's IsMdiContainer property to true
and set form1's MdiParent property to be form2 like so:
form2.IsMdiContainer = true;
form1.MdiParent = form2;
Of course, you cause the visual designer to write the first line for you by setting the property in the properties section:
EDIT
Here's an easy example.
Say you have 2 forms. FormContainer and FormChild.
FormContainer is the application's main form.
All you need to do is make sure that FormContainer's IsMdiContainer property is set to true and then you could add instances of other forms to this one by setting those instances' MdiParent property. Except for the main form, any instance of the Form class or a subclass is by default not visible.
public partial class FormContainer : Form {
public FormContainer() {
InitializeComponent();
this.IsMdiContainer = true;
// if you're not excited about the new form's backcolor
// just change it back to the original one like so
// note: The dark gray color which is shown on the container form
// is not it's actual color but rather a misterious' control's color.
// When you turn a plain ol' form into an MDIContainer
// you're actually adding an MDIClient on top of it
var theMdiClient = this.Controls
.OfType<Control>()
.Where(x => x is MdiClient)
.First();
theMdiClient.BackColor = SystemColors.Control;
}
private void FormContainer_Load(object sender, EventArgs e) {
var child = new FormChild();
child.MdiParent = this;
child.Show();
// if you wish to specify the position, size, Anchor or Dock styles
// of the newly created child form you can, like you would normally do
// for any control
child.Location = new Point(50, 50);
child.Size = new Size(100, 100);
child.Anchor = AnchorStyles.Top | AnchorStyles.Right;
}
}

How to position UserControl inside of a Panel when it is added at run-time?

I have a dialog form with a mixture of design-time and run-time added controls. Each of these controls is hosted in a Panel. Each panel has FillStyle.Top set.
At run time I add a UserControl to a panel:
public NetworkDiscoveryDialog(CSNetworkDiscovery networkDiscovery) : this()
{
NetworkDiscovery = networkDiscovery;
SnmpCommunitiesUserControl = new SnmpCommunitiesUserControl(NetworkDiscovery.SnmpCommunitiesSetting);
panel2.Controls.Add(SnmpCommunitiesUserControl);
}
public partial class SnmpCommunitiesUserControl : UserControl
{
public SnmpSetting SnmpSetting { get; set; }
public SnmpCommunitiesUserControl()
{
InitializeComponent();
Anchor = (AnchorStyles.Top | AnchorStyles.Left);
Dock = DockStyle.Fill;
}
public SnmpCommunitiesUserControl(SnmpSetting snmpSetting)
: this()
{
SnmpSetting = snmpSetting;
}
}
Unfortunately, SnmpCommunitiesUserControl does not have the same position as the controls which were added at design-time.
I have tried:
Setting the Panel's margin as well as well as padding.
Setting the UserControl's margin as well as padding.
Anchor and Dock settings.
None of these seem to have any effect on the run-time added UserControl.
Previously, I was passing a 'Location' parameter to my UserControl's constructor. This allowed me to set the Location of the UserControl, but was not a maintainable solution.
How should I be going about doing this?
EDIT:
My current solution is to nest a a second panel inside of the first panel. I clear all margins and padding for both panels. The parent panel has Dock.Top with its child have Dock.Fill. Then, I set the child's Left/Right padding to 10. This causes the run-time added control to appear in the proper place. I'm not happy with this solution, though.
You should set Location and Size Properties by yourself or you can set Dock property of the new control. Another way is change your host panel to the StackLayoutPanel or TableLayoutPanel.
If you want to set absolute position, u should set the Location property to your position and set dock to none.
control.Location = new Point(x, y);
control.Dock = DockStyle.None;

Iterating through tooltips

Guys, I have a windows form with a panel control and inside the panel control are several other controls with a System.Windows.Forms.Tooltip attached to them. How can I iterate through each tooltip and set the Active property of the tooltip to false? Tooltips, unlike other controls, are not actually controls. So I had this:
foreach (System.Windows.Forms.Control ctrl in this.pnlControl.Controls)
{
if (ctrl.Name.StartsWith("tt")) // since all my tooltip names start with 'tt'
{
System.Windows.Forms.ToolTip TipControl=(System.Windows.Forms.ToolTip)ctrl;
TipControl.Active=false;
}
}
This does not work though. It gets an error because the ToolTip control is not inherited from System.Windows.Forms.Control. Any ideas?
EDIT:
Okay Guys. I probably didn't go into enough detail to get the answer I needed. My problem is, I'm taking all the controls in my panel and moving them to a different panel. Once they are switched over, the tooltips are still attached to the controls, which is what I want. However I have no way to deactive or reactivate them once I move them since the form and the original panel no longer exist. However, I found a solution which I will post here.
How to add tool tips for two buttons? The correct way is NOT creating two instances of ToolTip in this way:
ToolTip tt1 = new ToolTip(); //or you can create one in the designer
tt1.ToolTipTitle = "test";
tt1.SetToolTip(button1, "caption1");
ToolTip tt2 = new ToolTip();
tt2.ToolTipTitle = "test2";
tt2.SetToolTip(button2, "caption2");
Remember that a ToolTip instance and a control are not one-on-one related. The right way for this example is:
ToolTip tt1 = new ToolTip(); //or you can create one in the designer
tt1.ToolTipTitle = "test";
tt1.SetToolTip(button1, "caption1");
tt1.SetToolTip(button2, "caption2");
To remove the tooltip of button2, use:
tt1.SetToolTip(button2,string.Empty);
For your case,we can use
foreach(Control c in this.Controls)
{
tt.SetToolTip(c,string.Empty);
}
Typically, you have a single ToolTip instance that handles the displaying of tool tips for all of your controls. That single ToolTip instance is just a regular member of your form. Simply set it's Active property to false.
Edit: OK, scrap my previous answer. Yes, ToolTip is a Component, not a Control, so it's not actually in the Panel at all. From your question, it sounds like you have one ToolTip instance and you use it for controls inside this Panel as well as for other controls, right? In that case the solution is simple: create a separate ToolTip instance and use that one for controls in the Panel, then just refer to it directly to deactivate it, eg.
ttPanel.Active = false;
Okay what I did was create a new class that is inherited from Control, like so:
public class TooltipMaster : System.Windows.Forms.Control
{
private System.Windows.Forms.ToolTip m_tooltip1;
private System.Windows.Forms.ToolTip m_tooltip2;
private System.Windows.Forms.ToolTip m_tooltip3;
private System.Windows.Forms.ToolTip m_tooltip4;
public System.Windows.Forms.ToolTip ToolTip1 {
get { return m_tooltip1; }
set { m_tooltip1 = value; }
}
public System.Windows.Forms.ToolTip ToolTip2 {
get { return m_tooltip2; }
set { m_tooltip2 = value; }
}
public System.Windows.Forms.ToolTip ToolTip3 {
get { return m_tooltip3; }
set { m_tooltip3 = value; }
}
public System.Windows.Forms.ToolTip ToolTip4 {
get { return m_tooltip4; }
set { m_tooltip4 = value; }
}
}
Then what I did was create an instance of this class inside my main form's Load event. Then I just assigned each of my 4 tooltips to the 4 tooltips in this class. Finally, I added this control to my panel. After doing all that, I could access the tooltips later by iterating through each control and looking for the TooltipMaster control.
Hope this makes sense!

Categories