I have some buttons that are inside of a panel, like the picture(1)
Its a user control.
I want that when somebody use my usercontrol, when resize the panel, the button size and the space of between them will change.
actually I want to have picture (3) but picture(2) will happend...
I set the anchar of panel, to right, left, top, botton. how to fix the buttons like picture 3?!
1 - Set 'MaximumSize' and 'MinimumSize' for all buttons in your user control.Something like this :
btnSave.MaximumSize = new Size(80, 30);
btnSave.MinimumSize = new Size(60, 30);
btnEdit.MaximumSize = new Size(80, 30);
btnEdit.MinimumSize = new Size(60, 30);
.
.
.
Or set from properties window.
2 - Set ' Anchor ' property for all buttons to Left,Right
3 - Write following code for 'Resize' event in your user control
private void UserControl1_Resize(object sender, EventArgs e)
{
int lastLeft = 0 , lastWidth = 0 ;
foreach (Control ctrl in this.Controls)
{
ctrl.Left = lastLeft + lastWidth + 3;
lastLeft = ctrl.Left;
lastWidth = ctrl.Width;
}
}
Note : Don't forget that you must cut the buttons from panel and paste them into user control.you don't need to panel and you can delete it.
Hope this be useful.
Related
I'm building that To-Do list app and I'm trying to create a "Add New task" button.
I wanted to create a new Task (TextBox) on the button click and also move the button bellow the TextBox added. So, I tried to create multiple panels and when the button was clicked, move the "New Task" button to the second panel and add the new textbox created to the first panel. And after that if the user wanted to remove that Task (TextBox), to repositionate the button and Tasks according to that.
Can someone please help me with that??
`
private void btnNewTask_Click(object sender, EventArgs e)
{
// Creating new Textbox
TextBox txtTask = new TextBox();
btnNewTask.Location = new Point(panel2);
// txtTask parameter
txtTask.BorderStyle = BorderStyle.None;
txtTask.ReadOnly = false;
txtTask.PlaceholderText = "Input a new Task.";
txtTask.Location = new Point(panel1);
//Adding txtTask.
this.Controls.Add(txtTask);
}
`
I founded The Solution. I deleted the panels and leaved the btnNewTask on the form.
On button click I needed to create and set the txtTask location as the btnNewTask location and change the Y location of btnNewTask to move it bellow. After that check if there was any other control that had the same or less Y location than txtTask, and if there was any, add 35 to his Y location too.
There is my new Code:
int c = 0;
private void btnNewTask_Click(object sender, EventArgs e)
{
// Creating new Textbox
TextBox txtTask = new TextBox();
// txtTask parameter
Font font = new Font("Segoe UI", 10.0f);
txtTask.Name = "txtTask" + ++c;
txtTask.BorderStyle = BorderStyle.None;
txtTask.ReadOnly = false;
txtTask.PlaceholderText = "Input a new Task.";
txtTask.Size = new Size(817, 31);
txtTask.Font = font;
txtTask.Location = new Point(btnNewTask.Location.X , btnNewTask.Location.Y); // txtTask will get the "btnNewTask" Location
btnNewTask.Location = new Point(txtTask.Location.X , btnNewTask.Location.Y + 35); // That should add 35 to the Y location
foreach (Control item in this.Controls)
{
if (item.Location.Y >= txtTask.Location.Y)
{ // if there is an item that has greater Y location
item.Location = new Point(item.Location.X, txtTask.Location.Y + 35); // It should increase its value as 35 too.
}
this.Controls.Add(txtTask);
}
There's an example:
Thank for the help and ideas!
The problem
I'm dynamically adding Buttons to the WinForm. As I do so, I'm repositioning existing Buttons to prevent overlap. The AutoSize property is being used to automatically set Width.
For longer text (that pushes Buttons beyond their default Width), the below code doesn't work.
For example:
b.Width is 75 before AutoSize is set
b.Width is 75 after AutoSize is set
When shifting other Buttons, it shifts them by b.Width + buffer = 83
However after addButton()completes, the AutoSize kicks in and sets the width to 150, overlapping the next Button which is only 83 pixels away instead of 158.
AutoSize appears to change the size of the control too late for it to be of use. How can I make it happen immediately?
Attempt 1 - Code
public void addButton(string text)
{
const int buffer = 8;
//Construct new button
Button b = new Button();
b.Text = text;
b.AutoSize = true;
b.Location = new Point(0, 0);
//Shift over all other buttons to prevent overlap
//b.Width is incorrect below, because b.AutoSize hasn't taken effect
for (int i = 0; i < Controls.Count; i++)
if (Controls[i] is Button)
Controls[i].Location = new Point(Controls[i].Location.X + b.Width + buffer, Controls[i].Location.Y);
Controls.add(b);
}
Attempt 2
Searched Google and StackOverflow for the following:
c# autosize immediately
c# autosize fast
c# autosize not working
Attempt 3
Asking here.
Last Resort
If nothing else works, a timer could be set to reposition Buttons on each tick. However this is very sloppy design, and doesn't aid in learning the intricacies of AutoSize. I'd like to avoid this workaround if possible.
The AutoSize and AutoSizeMode mode are applied only when the control is parented to the another control or form.
So invoke first
Controls.Add(b);
Now the b.Size will the adjusted accordingly and can be used in the calculations.
Alternatively, instead of Size property you can use the GetPreferredSize method to get the correct size without actually applying AutoSize and use it inside the calculations:
var bSize = b.GetPreferredSize(Size.Empty);
//Shift over all other buttons to prevent overlap
//b.Width is incorrect below, because b.AutoSize hasn't taken effect
for (int i = 0; i < Controls.Count; i++)
if (Controls[i] is Button)
Controls[i].Location = new Point(Controls[i].Location.X + bSize.Width + buffer, Controls[i].Location.Y);
The FlowLayoutPanel control does this work for you.
Place one on your form and try adding buttons in the following manner:
Button b = new Button();
b.AutoSize = true;
b.Text = text;
flowLayoutPanel1.SuspendLayout();
flowLayoutPanel1.Controls.Add(b);
flowLayoutPanel1.Controls.SetChildIndex(b, 0);
flowLayoutPanel1.ResumeLayout();
You can subscribe to the Resize event of the last button added. This will allow you to accurately change the locations of all of the buttons because now all of the buttons have been AutoSized.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var button1 = NewButton(0);
button1.Location = new Point(10, 10);
var button2 = NewButton(1);
button2.Location = new Point(button1.Right, 10);
var button3 = NewButton(2);
button3.Location = new Point(button2.Right, 10);
button3.Resize += (s, e) =>
{
button2.Location = new Point(button1.Right, 10);
button3.Location = new Point(button2.Right, 10);
};
Controls.Add(button1);
Controls.Add(button2);
Controls.Add(button3);
}
private Button NewButton(int index)
{
return new Button()
{
Text = "ButtonButtonButton" + index.ToString(),
AutoSize = true
};
}
}
I'm trying dynamically add panels within a panel dependent on the count of people in a list using the following code when the form loads:
private void Form1_Load(object sender, EventArgs e)
{
const int xConst = 2;
var people = new List<string>
{
"Person1",
"Person2",
"Person3",
"Person4",
};
var y = 2;
for (var x = 0; x < people.Count; x++)
{
var newpan = new MyPanel
{
BorderStyle = BorderStyle.None,
Height = 25,
Width = panel1.Width - 5,
Location = new Point(xConst, y)
};
var newlbl = new Label
{
BorderStyle = BorderStyle.None,
AutoSize = false,
Text = people[x],
Font = new Font("Segoe UI", 9.5F, FontStyle.Bold, GraphicsUnit.Point, ((byte)(0))),
Size = new Size(75,20),
Location = new Point(newpan.Location.X + 2, newpan.Location.Y + 2),
};
var newbtn = new Button
{
FlatStyle = FlatStyle.Flat,
FlatAppearance = { BorderSize = 0 },
UseVisualStyleBackColor = true,
Text = #"+",
Size = new Size(15,21),
Location = new Point(newpan.Width - 20,newpan.Location.Y - 1),
Font = new Font("Segoe UI", 9.0F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0)))
};
newpan.Controls.Add(newlbl);
newpan.Controls.Add(newbtn);
panel1.Controls.Add(newpan);
y += 27;
}
}
The problem is that if I specify the Location property in both the button and the label, only the first iteration of the labels and buttons show up for the Person1 iteration. But, if I leave the Location property out, they all show up. The problem with that is that I have a custom panel that overrides some stuff allowing me to put a customer border and color around the panels, and if I don't specify a location, the labels and buttons aren't positioned correctly on the panel, so it covers my border and looks sloppy.
Can someone help me figure out why this is happening? I've stepped through the program completely and watched all the values I can think of increment accordingly in the watch window. All the panels show up correctly, so I don't understand why their respective labels and buttons don't show up when I specify the location.
Looking at your code I notice that you are setting your newpan height to 25, and its position is offset by 27 with each iteration. You also are using
'Location = new Point(newpan.Location.X + 2, newpan.Location.Y + 2)
to set the location of your button and label within your newpan panel. newpan.Location is referenced in the coordinates of your panel1, your button and label's location is referenced in the coordinates of your newpan panel therefore after the first iteration of your For statement your label and buttons y location value is 29 which is greater than the height of your newpan panel making it not able to be seen, the next iteration after that will be y will be 56 and so forth. Each content control, in this case your panels will have its own coordinate system, the easiest fix would be to do something like this:
'Location = new Point( 2, 2) //for your label
'Location = new Point(newpan.Width - 20, - 1) //for your button
The other alternative is to do like jmcilhinney suggests and make an UserControl with your button and label already in position, you would then create individual instances of it and assign it to your panel1.
I got a form. In this form there is a tab control and there is a menu strip. I would like the tab control to take up the space of the entire form; however, I do not want the menu strip to cover the top of it.
In order to combat this problem. I made a control and I made the panel the same size as the menu strip. I put added the panel control to the menu strip first and then I added the tab control; however, I did not get the desired result. Can someone show me how to get the result I desire?
This is what it looks like without the additional panel.
Here us the code :
public Main()
{
InitializeComponent();
//Panel placeholder = new Panel()
//{
// MaximumSize = menuStrip1.MaximumSize,
// MinimumSize = menuStrip1.MaximumSize,
// Size = menuStrip1.Size,
// Padding = menuStrip1.Padding,
// Visible = true,
//};
//placeholder.Dock = DockStyle.Top;
//Controls.Add(placeholder);
Controls.Add(InitNavigation());
}
TabControl InitNavigation()
{
//Declare All Variables
TabControl control = new TabControl();
TabPage queryPage = new TabPage();
TabPage tablePage = new TabPage();
control.TabPages.Add(queryPage);
control.TabPages.Add(tablePage);
//Customize Table Control
control.Top = menuStrip1.Size.Height;
control.Dock = DockStyle.Fill;
Padding Margin = control.Margin;
MessageBox.Show("" + menuStrip1.Size.Height);
//control.Margin = new Padding(Margin.Left,, Margin.Right, Margin.Bottom);
//Customize Query Tab
queryPage.Text = "Queries";
//Customize Table Page
tablePage.Text = "Tables";
control.Visible = true;
return control;
}
This is what it looks like with the panel
Here is the code:
public Main()
{
InitializeComponent();
Panel placeholder = new Panel()
{
MaximumSize = menuStrip1.MaximumSize,
MinimumSize = menuStrip1.MaximumSize,
Size = menuStrip1.Size,
Padding = menuStrip1.Padding,
Visible = true,
};
placeholder.Dock = DockStyle.Top;
Controls.Add(placeholder);
Controls.Add(InitNavigation());
}
TabControl InitNavigation()
{
//Declare All Variables
TabControl control = new TabControl();
TabPage queryPage = new TabPage();
TabPage tablePage = new TabPage();
control.TabPages.Add(queryPage);
control.TabPages.Add(tablePage);
//Customize Table Control
control.Top = menuStrip1.Size.Height;
control.Dock = DockStyle.Fill;
Padding Margin = control.Margin;
MessageBox.Show("" + menuStrip1.Size.Height);
//control.Margin = new Padding(Margin.Left,, Margin.Right, Margin.Bottom);
//Customize Query Tab
queryPage.Text = "Queries";
//Customize Table Page
tablePage.Text = "Tables";
control.Visible = true;
return control;
}
finally. This last picture just shows that the tabs are in fact there (its the same code as the first code posted except the menu strip visibility is set to false).
Any insight on how to fix this problem would be appreciated
If the fully docked control is underneath a top docked control, try bringing the fully docked control to the front (right click on it in the designer and select bring to front) this should fix it.
i dynamic populate a dock panel with answers from database and another dock panel with questions from the database as well. the answers will be populated as Labels and i trying to do a drag and drop with labels to textblock . Yes i can drag and drop , but the thing is i want to drag the label too . For example if the Label content is Hello , i want the hello to be dragged over with the word " hello " as well , for now , when i drag it , it doesn't drag the word as well , but when i drop it into a textbox , the word " hello " is dropped . I want to drag the animation or word as well together with the cursor .
this is my code :
private void PopulateQuestion(int activityID, int taskID)
{
IList<Model.question> lstQuestion = qn.GetRecords(taskID, activityID);
StackPanel sp = new StackPanel();
StackPanel stp = new StackPanel();
foreach (Model.question qhm in lstQuestion)
{
StackPanel sp1 = new StackPanel() { Orientation = Orientation.Horizontal }; // Question
TextBlock tb = new TextBlock();
tb.Text = qhm.QuestionContent;
tb.FontWeight = FontWeights.Bold;
tb.FontSize = 24;
sp1.Children.Add(tb);
StackPanel sp2 = new StackPanel() { Orientation = Orientation.Horizontal }; // Answer
Label tb1 = new Label();
tb1.Content = qhm.Answer;
tb1.FontWeight = FontWeights.Bold;
tb1.FontSize = 24;
tb1.MouseLeftButtonDown += tb1_Click;
sp2.Children.Add(tb1);
TextBox tbox = new TextBox();
tbox.Width = 100;
tbox.FontSize = 24;
tbox.AllowDrop = true;
tbox.FontWeight = FontWeights.Bold;
if (qhm.Answer.Trim().Length > 0 )
{
sp1.Children.Add(tbox);
}
sp.Children.Add(sp1);
stp.Children.Add(sp2);
}
dockQuestion.Children.Add(sp);
dockAnswer.Children.Add(stp);
}
private void tb1_Click(object sender, RoutedEventArgs e)
{
Label lbl = (Label)sender;
DataObject dataObj = new DataObject(lbl.Content);
DragDrop.DoDragDrop(lbl, dataObj, DragDropEffects.All);
lbl.IsEnabled = false;
lbl.Foreground = (SolidColorBrush)new BrushConverter().ConvertFromString("#FFFB3B46"); // Red
}
You can follow the strategy outlined in the link below, which essentially creates a new window and causes the window position to be updated with the mouse cursor.
http://blogs.msdn.com/b/jaimer/archive/2007/07/12/drag-drop-in-wpf-explained-end-to-end.aspx
So the main points from the page are that you decorate the cursor using the Adorner.
You can use the this.DragSource.GiveFeedback and other events on the DragSource event handlers to set up the Adorner.
Once you have the event handler, that gives you the opportunity to do something.
//Here we create our adorner..
_adorner = new DragAdorner(DragScope, (UIElement)this.dragElement, true, 0.5);
_layer = AdornerLayer.GetAdornerLayer(DragScope as Visual);
_layer.Add(_adorner);
So you can create your own Adorner by subclassing it. You can find more info on creating a custom adorner here:
http://msdn.microsoft.com/en-us/library/ms743737.aspx
take a look at this
http://blogs.msdn.com/b/adamroot/archive/2008/02/19/shell-style-drag-and-drop-in-net-wpf-and-winforms.aspx
the default wpf drag & drop's animation is ugly, if you want be show some text or image while dragging,you need
do something more.