running this in linux, all fine.
running in Windows making trouble, all tabs are twice present and i can't insert content into tabs.
https://abload.de/img/unbenannt82jfh.png
someone knows about?
public class CalendarApp : Form {
public CalendarApp() : base() {
tabControl = new TabControl();
tabPages = new TabPage[3];
string []tabText = {"Haupt", "Kontakte", "Termine"};
for (int i=0; i<3; i++) {
Console.WriteLine ("Ahhh windoof: {0}", i);
tabPages[i]=new TabPage();
tabPages[i].Text = tabText[i];
tabPages[i].TabIndex = i;
tabPages[i].Parent = tabControl;
tabControl.Controls.Add(tabPages[i]);
}
FlowLayoutPanel mainPanel = new FlowLayoutPanel();
tabControl.Size = new Size(mainPanel.Size.Width+8, mainPanel.Size.Height+24);
this.Text = "CalendarApp";
Controls.Add (tabControl);
AutoSize=true;
this.FormBorderStyle = FormBorderStyle.FixedSingle;
ResumeLayout(false);
PerformLayout();
}
[STAThread]
public static void Main() {
Application.Run(new CalendarApp());
}
private TabControl tabControl;
private TabPage []tabPages;
}
ok, i've yust found the Problem:
// tabPages[i].Parent = tabControl; <-this Line is causing the Problem
tabControl.Controls.Add(tabPages[i]);
Related
simple question here:
I have a problem with one of my labels.
My problem is that the (!!!) label corresponding to the textbox "Datei Name" is being blocked by said textbox. Is there a setting that I have missed that puts said label behind/in front of the textbox?
How the (this part of the) program works:
When something is incorrectly entered in one of the textboxes a label containing (!!!) and a Messagebox show up which tell the user where the error is located.
As i mentioned in the comment to the question, i'd use ErrorProvider instead of spending time to write code to manipulate controls on the form.
Here is MSDN example: How to: Display Error Icons for Form Validation with the Windows Forms ErrorProvider Component
How it works?
When the form is NOT valid, you'll see:
When you move cursor over icon, you'll see error details:
If you've got LinqPad, you can use this script to check how it works:
void Main()
{
MyForm mf = new MyForm();
mf.Show();
}
// Define other methods and classes here
public class MyForm: Form
{
private TextBox TxtDateiName = null;
private TextBox TxtDateiNr = null;
private Label Label1 = null;
private Label Label2 = null;
private Button BtnValidate = null;
Dictionary<Control, ErrorProvider> ValidatedControls = null;
public MyForm()
{
Initialize();
}
private void Initialize()
{
this.Size = new Size(250, 180);
this.MinimizeBox = false;
this.MaximizeBox = false;
this.Text = "ErrorProvider Example";
Label1 = new Label(){Text="Datei Name:", Location =new Point(10,12), AutoSize = true};
Label2 = new Label(){Text="Datei Nr:", Location =new Point(10,42), AutoSize = true};
TxtDateiName = new TextBox(){Name="TxtDateiName", Size= new Size(140,24), Location =new Point(78,10)};
TxtDateiNr = new TextBox(){Name="TxtDateiNr", Size= new Size(140,24), Location =new Point(78,42)};
BtnValidate = new Button(){Size = new Size(220, 48), Text = "Validate", Location = new Point(10, 78) };
BtnValidate.Click += BtnValidate_Click;
this.Controls.Add(Label1);
this.Controls.Add(Label2);
this.Controls.Add(TxtDateiName);
this.Controls.Add(TxtDateiNr);
this.Controls.Add(BtnValidate);
ValidatedControls = new Dictionary<Control, ErrorProvider>();
ValidatedControls.Add(TxtDateiName, new ErrorProvider(this));
ValidatedControls.Add(TxtDateiNr, new ErrorProvider(this));
ValidatedControls[TxtDateiName].SetIconAlignment(TxtDateiName, ErrorIconAlignment.MiddleRight);
ValidatedControls[TxtDateiName].SetIconPadding (TxtDateiName, 2);
ValidatedControls[TxtDateiName].BlinkRate = 1000;
ValidatedControls[TxtDateiName].BlinkStyle = System.Windows.Forms.ErrorBlinkStyle.AlwaysBlink;
ValidatedControls[TxtDateiNr].SetIconAlignment(TxtDateiName, ErrorIconAlignment.MiddleRight);
ValidatedControls[TxtDateiNr].SetIconPadding (TxtDateiName, 2);
ValidatedControls[TxtDateiNr].BlinkRate = 1000;
ValidatedControls[TxtDateiNr].BlinkStyle = System.Windows.Forms.ErrorBlinkStyle.AlwaysBlink;
}
private void BtnValidate_Click(object sender, EventArgs e)
{
bool ans = true;
foreach(var k in ValidatedControls.Keys)
{
switch(k.Name)
{
case "TxtDateiName":
ans = IsValidName(((TextBox)k).Text);
ValidatedControls[k].SetError(k, ans ? "" : "Name is wrong!");
break;
case "TxtDateiNr":
ans = IsValidNumber(((TextBox)k).Text);
ValidatedControls[k].SetError(k, ans ? "" : "Number is wrong!");
break;
}
}
ans = ValidatedControls.All(kvp=>kvp.Value.GetError(kvp.Key)=="");
MessageBox.Show(ans ? "Form is valid!" : "Form contains errors!", "Information");
if(ans) this.Close();
}
private bool IsValidName(string dName)
{
return Regex.IsMatch(dName, #"^(\w{3,})$");
}
private bool IsValidNumber(string dNumber)
{
return Regex.IsMatch(dNumber, #"^(\d{3,5})$");
}
}
Do not forget to add references (F4) to: System.Windows.Forms.dll
and then add the following namespaces:
System.Drawing
System.Windows.Forms
Final note:
This is just an example. So, the code is not optimized.
The controls with Handles not yet created seem to be pushed to the bottom of their Parent Control when the TabControl's Padding property is changed. Looking at the .NET source code, Padding makes a call to RecreateHandle();, which seems to have something to do with it.
Below is code that illustrates the problem. Each checkbox has a corresponding label just below it. Some of the labels are visible at the start, some are hidden. Checking the person0 checkbox makes the person0 label appear, but incorrectly at the bottom. Instead, the person0 label should appear just underneath the person0 checkbox, which is the order it was added to the FlowLayoutPanel. See screenshot.
The code provides a bool doWorkaround option, but there must be a better way. Forcing all the Handles to be created using CreateControl() seems not correct either.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
namespace WindowsFormsApplication3 {
public class TabControl3 : TabControl {
private bool doWorkaround = false; // set to true to prevent the bug
protected override void OnFontChanged(EventArgs e) {
base.OnFontChanged(e);
int h = (int) this.Font.Height;
SetPadding(new Point(h, h)); // calling this causes the Controls to re-order incorrectly
}
///<summary>Setting the padding causes the TabControl to recreate all the handles, which causes the hidden handleless controls to rearrange.</summary>
public virtual void SetPadding(Point pt) {
// Workaround solution: remove all controls from tab pages and then add them back after.
int n = TabPages.Count;
Control[][] arr = null;
if (doWorkaround) {
arr = new Control[n][];
for (int i = 0; i < n; i++) {
TabPage tp = TabPages[i];
arr[i] = tp.Controls.Cast<Control>().ToArray();
tp.Controls.Clear();
}
}
this.Padding = pt; // in the .NET source code, setting Padding calls RecreateHandle()
if (doWorkaround) {
for (int i = 0; i < n; i++)
TabPages[i].Controls.AddRange(arr[i]);
}
}
}
public class CheckBox2 : CheckBox {
public CheckBox2(String text, bool isChecked = false) : base() {
this.Text = text;
this.AutoSize = true;
this.Checked = isChecked;
}
}
public class Label2 : Label {
public Label2(String text) : base() {
this.Text = text;
this.AutoSize = true;
}
}
public class MyForm : Form {
TabControl tc = new TabControl3 { Dock = DockStyle.Fill };
public MyForm() {
this.Size = new System.Drawing.Size(600, 800);
this.StartPosition = FormStartPosition.CenterScreen;
TabPage tp1 = new TabPage("Page1");
FlowLayoutPanel p = new FlowLayoutPanel { FlowDirection = System.Windows.Forms.FlowDirection.TopDown, Dock = DockStyle.Fill };
p.Controls.Add(new CheckBox2("Person0"));
p.Controls.Add(new Label2("Person0") { Visible = false });
p.Controls.Add(new CheckBox2("Person1", true));
p.Controls.Add(new Label2("Person1"));
p.Controls.Add(new CheckBox2("Person2", true));
p.Controls.Add(new Label2("Person2"));
p.Controls.Add(new CheckBox2("Person3"));
p.Controls.Add(new Label2("Person3") { Visible = false });
p.Controls.Add(new CheckBox2("Person4"));
p.Controls.Add(new Label2("Person4") { Visible = false });
for (int i = 0; i < p.Controls.Count; i += 2) {
CheckBox cb = (CheckBox) p.Controls[i];
Label lb = (Label) p.Controls[i+1];
cb.CheckedChanged += delegate {
bool b = cb.Checked;
lb.Visible = b;
};
}
tp1.Controls.Add(p);
tc.TabPages.Add(tp1);
Controls.Add(tc);
}
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
this.Font = SystemFonts.MenuFont; // to trigger the bug
}
}
static class Program {
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyForm());
}
}
}
I tested using .NET 3.5, 4, 4.52 and saw the same behavior in all three.
Here is my code:
RadScrollablePanel panel = new RadScrollablePanel() { AutoScroll = true, Dock = DockStyle.Fill};
pnlclp.PanelContainer.Controls.Add(panel);
foreach (var date in dates)
panel.Controls.Add(new ucDetails() { Dock = DockStyle.Left });
I'm adding some controls inside a RadScrollablePanel and then adding it into a PanelContainer.
Everything works great. If I add so many controls inside the RadScrollablePanel which is not visible in first look, the scroll bar will be shown as well.
But If I change the DockStyle.Left to DockStyle.Right in foreach loop, after loading the controls, it will not show the scroll bar and it is strange and I can not find any reason or solution to solve this issue.
I even try to change the RightToLeft property of RadScrollablePanel. but no success :(
Any suggestion?
Following the provided information, I have prepared a sample project to test the behaior in RadScrollablePanel.
I have logged it in our feedback portal by creating a public thread. You can track its progress, subscribe for status changes and add your comments on the following link: https://feedback.telerik.com/winforms/1453253-radscrollablepanel-missing-scrollbar-when-there-is-no-enough-space-to-display-the-content-controls
I hope this information helps.
To work around this problem of the standard Microsoft WinForms Panel, I can suggest docking all the UserControls to the Left and use an empty Panel that occupies all the available space on the left of the form, so exactly the same behavior as all UserControls are docked to the Right. When the size of the form is changed adjust the width of the empty panel. The described approach is illustrated with the code below:
public partial class Form1 : Form
{
UserControl1[] userControls;
RadScrollablePanel parentPanel;
Panel spacePanel;
public Form1()
{
InitializeComponent();
new Telerik.WinControls.RadControlSpy.RadControlSpyForm().Show();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.parentPanel = new RadScrollablePanel();
this.parentPanel.Dock = DockStyle.Fill;
this.parentPanel.BackColor = Color.Yellow;
this.Controls.Add(this.parentPanel);
this.parentPanel.AutoScroll = true;
int count = 10;
this.userControls = new UserControl1[count];
for (int i = 0; i < count; i++)
{
this.userControls[i] =
new UserControl1()
{
Dock = DockStyle.Left,
BackColor = Color.FromKnownColor((KnownColor)(i + 50))
};
this.parentPanel.Controls.Add(this.userControls[i]);
}
this.spacePanel = new Panel();
this.spacePanel.Dock = DockStyle.Left;
this.parentPanel.Controls.Add(this.spacePanel);
}
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
if (this.spacePanel != null)
{
int lastPanelWidth = this.parentPanel.Width;
foreach (Control control in this.parentPanel.PanelContainer.Controls)
{
if (control.Dock == DockStyle.Left && control != this.spacePanel)
{
lastPanelWidth -= control.Width;
}
}
if (lastPanelWidth < 0)
{
lastPanelWidth = 0;
}
this.spacePanel.Width = lastPanelWidth;
}
}
}
I am having trouble with dynamically adding a class of controls that should when working look like this:
When a new one is added it should appear in the left panel under the toolstrip.
So far I am having trouble making them appear (The one in the middle is just the design I made).
Here is the code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//Problem Occurs Here
EquationBox[] EquationBoxArray = new EquationBox[12];
for (int x = 0; x < 12; x++)
{
EquationBoxArray[x] = new EquationBox();
ActiveForm.Controls.Add(EquationBoxArray[x].mainPanel);
ActiveForm.Controls.Add(EquationBoxArray[x].colorPanel);
}
}
private void add_line_Click(object sender, EventArgs e) //Add Line
{
}
private void clear_Click(object sender, EventArgs e) //Clear Lines
{
}
}
public class EquationBox
{
public Panel colorPanel = new Panel();
public Panel mainPanel = new Panel();
public TextBox equationBox = new TextBox();
public CheckBox isVisibleBox = new CheckBox();
public EquationBox()
{
mainPanel.Size = new Size(200, 72);
colorPanel.Size = new Size(33, 72);
mainPanel.Location = new Point(50, 50);
colorPanel.Location = new Point(50, 50);
colorPanel.BackColor = Color.Red;
}
}
The problem occurs here:
//Problem Occurs Here
EquationBox[] EquationBoxArray = new EquationBox[12];
for (int x = 0; x < 12; x++)
{
EquationBoxArray[x] = new EquationBox();
ActiveForm.Controls.Add(EquationBoxArray[x].mainPanel);
ActiveForm.Controls.Add(EquationBoxArray[x].colorPanel);
}
When I run it, it return with:
Additional information: Cross-thread operation not valid: Control '' accessed from a thread other than the thread it was created on.
And even before that started happening, the EqautionBox wouldn't appear.
Thanks in advance, this is really troubling me.
For the constructor of EquationBox:
public EquationBox()
{
mainPanel.Size = new Size(200, 72);
colorPanel.Size = new Size(33, 72);
mainPanel.Location = new Point(50, 50);
colorPanel.Location = new Point(50, 50);
colorPanel.BackColor = Color.Red;
}
First, your control appeared, but mainPanel is overlap colorPanel and you can't see mainPanel (same BG color as your form), so swap which added first solved
EquationBox[] EquationBoxArray = new EquationBox[12];
for (int x = 0; x < 12; x++)
{
EquationBoxArray[x] = new EquationBox();
this.Controls.Add(EquationBoxArray[x].colorPanel);
this.Controls.Add(EquationBoxArray[x].mainPanel);
}
I am using this.Controls, not sure about the ActiveForm.Controls part, maybe on constructing, your Form1 is not the active one, so error occured.
Ps: I suggest add colorPanel to mainPanel, and only add mainPanel to Form. And UserControl is a good solution here as Steve Wellens said.
There are various issues with EquationBox the TextBox and CheckBox are not in the panel. It would be easier to make it a UserControl.
Then to do the positioning use a FlowLayoutPanel.
The Set Up:
I have a System.Windows.Forms class called ProjectForm. In this form I have a TabControl called tabControl. When the form is initialized, so is the tabControl; however, the tabControl has no TabPages loaded. TabPages are created and loaded at runtime on demand when a user selects an item in a treeView control.
Example Call From ProjectForm:
this.tabControl.TabPages.Add(PageLibrary.CallStackPage(e.Node.Name, e.Node.Text));
(TabPageLibrary) as PageLibrary Class reference
class TabPageLibrary
{
private TabPageToolBar tabToolBar = new TabPageToolBar();
public TabPage CallStackPage(string name, string label)
{
TabPage tabPage = NewProjectPage();
tabPage.Name = "STACK:" + name;
tabPage.Text = label;
tabPage.Tag = name;
tabPage.ImageKey = "viewstack.png";
return tabPage;
}
private TabPage NewProjectPage()
{
TabPage tabPage = new TabPage();
tabPage.Padding = new Padding(3);
tabPage.UseVisualStyleBackColor = true;
tabPage.Controls.Add(this.tabToolBar);
return tabPage;
}
}
Problem
When the TabPage is loaded into the control at runtime - no image shows on the tab. the TabControl.ImageList is set to an ImageList that does contain the image I am referencing. Subsequently, the tree control is referencing the same ImageList and the images do show in the tree control.
I would be grateful for any suggestions, solutions or blinding flashes of the obvious you could share.
--Peace
+++ FIX UPDATE ++++
With DonBoitnott's insight - I was able to get these images to properly render with minor refactoring.
New Example Call From ProjectForm:
TabPage page = PageLibrary.NewProjectPage();
this.tabControl.TabPages.Add(page);
page = PageLibrary.CallStackPage(e.Node.Name, e.Node.Text, page);
Refactored (TabPageLibrary) as PageLibrary Class reference
class TabPageLibrary
{
private TabPageToolBar tabToolBar = new TabPageToolBar();
internal TabPage CallStackPage(string name, string label, TabPage page)
{
page.Name = "STACK:" + name;
page.Text = label;
page.Tag = name;
page.ImageKey = "viewstack.png";
//TODO: Load Additional CallStack Controls
return page;
}
internal TabPage NewProjectPage()
{
TabPage tabPage = new TabPage();
tabPage.Padding = new Padding(3);
tabPage.UseVisualStyleBackColor = true;
tabPage.Controls.Add(this.tabToolBar);
return tabPage;
}
}
Thanks again #DonBoitnott, works like a champ!
The code for TabPage tells us that the page will only pick up the image list if it has a parent from which to pull it. Odd, but you can prove it. Here it is:
//From TabPage.cs
public string ImageKey
{
get
{
return this.ImageIndexer.Key;
}
set
{
this.ImageIndexer.Key = value;
TabControl parentInternal = this.ParentInternal as TabControl;
if (parentInternal != null)
{
this.ImageIndexer.ImageList = parentInternal.ImageList;
}
this.UpdateParent();
}
}
That means you have to ensure you parent the tab page before you attempt to assign the image list key.
So, with that in mind, here's a bare bones example you can put in any form (you'll need to supply your own art, of course):
public partial class Form1 : Form
{
private ImageList _imgList;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(Object sender, EventArgs e)
{
foreach (TabPage p in tabControl1.TabPages)
p.Dispose();
_imgList = new ImageList();
_imgList.Images.Add("image0", Properties.Resources.ImageOne);
_imgList.Images.Add("image1", Properties.Resources.ImageTwo);
_imgList.Images.Add("image2", Properties.Resources.ImageThree);
tabControl1.ImageList = _imgList;
}
private void button1_Click(Object sender, EventArgs e)
{
Int32 count = tabControl1.TabPages.Count;
if (count < 3)
{
TabPage p = new TabPage();
p.Name = "page" + count;
p.Text = "page" + count;
tabControl1.TabPages.Add(p);
p.Parent = tabControl1;
p.ImageKey = "image" + count;
}
}
}