I need some help changing the position of an item on another form dynamically.
I am trying to make a skin design tool for an app I'm making and need to know how to process an event from one form to another.
What I would like to do is set some initial variables in some text boxes and hit a preview button this will open a new form and display the skin.
Then I would like to be able to fine tune the positions of the items by clicking buttons on the 1st form.
I am ok with getting the initial positions on form2 from form1 I do it like this.
Form1 form1 = (Form1)Application.OpenForms["Form1"];
int xPos = 0;
int yPos = 0;
if (int.TryParse(form1.textBox1.Text, out xPos))
if (int.TryParse(form1.textBox2.Text, out yPos))
button1.Location = new Point(xPos,yPos);
And my button code in form1 to increase the position is this.
Form2 PreviewWindow = new Form2();
int newText;
int xPos = 0;
int yPos = 0;
if (int.TryParse(textBox1.Text, out xPos))
if (int.TryParse(textBox2.Text, out yPos))
PreviewWindow.button1.Location = new Point(xPos + 1 , yPos);
newText = xPos + 1;
textBox1.Text = newText.ToString();
But now I'm stuck on updating the event to the 2nd form.Would any of you mind giving me some pointers?
The second code doesn't work because you're creating a new instance of Form2. Try this instead
Form2 PreviewWindow = (Form2)Application.OpenForms["Form2"];
int newText;
int xPos = 0;
int yPos = 0;
if (int.TryParse(textBox1.Text, out xPos))
if (int.TryParse(textBox2.Text, out yPos))
PreviewWindow.button1.Location = new Point(xPos + 1 , yPos);
newText = xPos + 1;
textBox1.Text = newText.ToString();
Your best bet here will be to expose properties and/or methods in the form you wish to control. For a TextBox position, for instance:
//Property option:
public Int32 TextBox1XPos
{
get
{
return textBox1.Location.X;
}
set
{
textBox1.Location.X = value;
}
}
public Int32 TextBox1YPos
{
get
{
return textBox1.Location.Y;
}
set
{
textBox1.Location.Y = value;
}
}
//Method option
public void MoveTextBox1(Int32 XPos, Int32 YPos)
{
textBox1.Location = new Point(XPos, YPos);
}
You can implement these for any property on the form. This gives you an indirect way of communicating with the form and doesn't require setting all controls to Public exposure.
Related
I have a windows form in C# project that keeps some information. I created a bunch of textbox and combobox dynamically, depend upon user input.
So here there is two rows since user has given the input as 2. All the components in the image are dynamically created. For each component i have created a class to set the property and its behaviour.
Now the issue is I need to traverse the component using tab.
When i tried to set tabindex = 1 for the first textbox and tabindex = 2 for the second textbox. I'm traversing the components vertically like mentioned below
Actual Output : enter image description here
The code in which i have added are following.
public class addDynamicCptboxComponents : add_components
{
public override void add_dynamic_components(int getNoOfTxtBox, int pointX, int pointY, Form1 f)
{
TextBox txtBox = new TextBox();
f.panel1.Controls.Add(txtBox);
txtBox.Location = new Point(pointX, pointY);
txtBox.Size = new System.Drawing.Size(75, 23);
f.panel1.Controls.Add(txtBox);
txtBox.Name = "Add_txtBox" + getNoOfTxtBox;
//assigned the tabindex as 2 for the second textbox
txtBox.TabIndex = 2;
}
}
public class addDynamicDateofServiceComponents : add_components
{
public override void add_dynamic_components(int getNoOfTxtBox, int pointX, int pointY, Form1 f)
{
TextBox txtBox = new TextBox();
f.panel1.Controls.Add(txtBox);
txtBox.Location = new Point(pointX, pointY);
txtBox.Size = new System.Drawing.Size(75, 23);
f.panel1.Controls.Add(txtBox);
txtBox.Name = "Add_dos_txtBox" + getNoOfTxtBox;
//assigned the tabindex as 1 for first textbox
txtBox.TabIndex = 1;
}
}
But what i need is , I need to traverse the components horizontally as mentioned below.
Expected Ouput: enter image description here
The Requried tab order is specified in the above image.
Guessing from the name of your class you are adding rows dynamically to your form. But since you are hard coding the tab index the result per row looks like in your expected output. This means by tabbing you go from index 1 to index 1 to index 2 to index 2 and so on and so forth.
I'd advise you to have an incrementing tab index stored somewhere in your application which is incremented after it is assigned to a new dynamically created control.
As a really simple example I created a fresh forms project which just has two buttons. The first one adds a new textbox and the second button switches into a new row. And in this example everything has the tab index you require. The code behind looks like this:
public partial class Form1 : Form
{
private int currentX = 0;
private int currentY = 0;
private const int tbWidth = 75;
private const int tbHeight = 23;
private int currentTabIndex = 0;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var textBoxOne = new TextBox();
this.Controls.Add(textBoxOne);
textBoxOne.Location = new Point(this.currentX, this.currentY);
textBoxOne.Size = new Size(tbWidth, tbHeight);
textBoxOne.TabIndex = currentTabIndex;
textBoxOne.Text = $"{currentTabIndex}";
currentTabIndex++;
this.currentX += tbWidth + 5;
}
private void button2_Click(object sender, EventArgs e)
{
currentY += tbHeight + 5;
currentX = 0;
}
}
Please bare in mind this is just a simple example. I could help you better in the context of your application if I knew more about it.
public void ItemGot()
{
number = number + 1; //Increment by 1
quantity.Text = ("x" + number); //Overwrite Text
quantity.Refresh(); //Updates the text
}
Hello, I have this code above. When this method runs, the text of a label I set up earlier should change the text to the one i set below. However, its not doing it. Furthermore, by setting breakpoints in Visual Studio, I have determined that:
The method is being called,
Number is being incremented properly.
There should be NO reason why this not working, because the program is recognizing that number is increasing by one. My friend said a similar question here. Still no help, and now that code is outdated. Please help!
EDIT: how I added the quantity label
First, I initialized it in the constructor: public Label quantity;
Then I did this: quantity = new Label();
Lastly, in another method, I gave the quantity the following properties:
quantity.Size = new Size(24, 24);
quantity.Text = ("x" + number);
quantity.Left = 48;
Controls.Add(quantity);
number is also in the constructor and is set to 0.
EDIT 2 : I'll Post my whole method
public InventoryScreen()
{
btnItems = new Button();
quantity = new Label();
//call the methods for spawning the buttons
ButtonGenItems(cNumber, btnItems, quantity);
InitializeComponent();
}
public void InventoryScreen_Load(object sender, EventArgs e)
{
}
#region ButtonGenItems Method
public void ButtonGenItems(int cNumber, Button btnItems,Label quantity)
{
int xPos = 126;
int yPos = 25;
for (int n = 0; n < 1; n++)
{
btnItems.Tag = n;
btnItems.Size = new Size(48, 52); //Button size X and Y
btnItems.BackColor = Color.CornflowerBlue;
quantity.Size = new Size(24, 24);
quantity.Text = ("x" + number);
if (yPos > 60) // Five Buttons in one column
{
yPos = 25; //spawn position Y
xPos = xPos + btnItems.Width + 10; //spacing X
}
btnItems.Left = xPos; //Start Button spawn at the Left side
btnItems.Top = yPos; //Start spawn at the top side
quantity.Left = 48;
quantity.Top = 60;
yPos = yPos + btnItems.Height + 10;
btnItems.Text = "Use";
Controls.Add(btnItems); //place Buttons
Controls.Add(quantity);
// the Event of click Button
//btnItems.Click += new System.EventHandler(ItemUse); //to be implimented
}
}
#endregion
public void ItemGot()
{
//*Interestingly, the program recognizes that 'number' is increasing by 1, but label won't update the text
//Furthermore, pressing the actual button will trigger the text update, but simulating a buttonclick WONT DO ANYTHING
Console.WriteLine("Text should now increment by 1"); //Debugging to test method
number = number + 1; //Increment by 1
quantity.Text = ("x" + number); //Overwrite Text
}
}
2.5 This is how the method is being called. This method is located in another class
public void Update(Vector2 pos)
{
this.position = pos; //get char position
Inv = new InventoryScreen(); //create instance of object
charRange = new Rectangle((int)position.X, (int)position.Y, 64, 57); //create rectangle
//Intersection Code, If the character intersects with the item while the item is showing, run below
if (alive && charRange.Intersects(itemRect))
{
alive = false; //stop showing the item
Inv.ItemGot(); //Call the ItemGot class, which adds the item to the inventory screen
}
}
As I understand you have already open/showed form(instance of class InventoryScreen) with your label when you calling Update method, But...
Inside of method Update you creating a new instance of InventoryScreen, and calling function ItemGot with this new instance of form.
I think you need to pass reference of your current instance of InventoryScreen in method Update, then use that reference for calling ItemGot method
public void Update(Vector2 pos, InventoryScreen invscreen)
{
this.position = pos;
charRange = new Rectangle((int)position.X, (int)position.Y, 64, 57);
if (alive && charRange.Intersects(itemRect))
{
alive = false;
invscreen.ItemGot();
}
}
I am having some issues making my label show up in the gui... any thoughts?
private void addNewExcerciseButton_Click(object sender, EventArgs e)
{
int y = 305;
int x= 61;
string tempExcercise = excerciseTextBox.Text;
excerciseTextBox.Clear();
Label[] excerciseLabels = new Label[numExercises];
for (int i = 0; i < numExercises; ++i)
{
excerciseLabels[i] = new Label();
excerciseLabels[i].Text = ToString("{0}. {1}", i + 1, tempExcercise);;
excerciseLabels[i].Location = new System.Drawing.Point(x, y);
x += 10;
y += 10;
++numExercises;
}
}
thanks in advance.
numExercises is global.
You have to add each new Label to the collection of Controls contained by a visible Control (such as your Form). You're creating and setting them up, but they aren't part of the GUI yet until they're in the control hierarchy.
Add the following line after setting the location of the label:
this.Controls.Add(exerciseLabels[i]);
You need to add the label to the GUI:
this.Controls.Add(excersizeLabels[i]);
As a side note, there is no point in using an array.
I'm looking to implement a Visual Studio-style undo drop-down button:
I've looked all over the internet, and can't seem to find any real implementations of this.
I've started by deriving from ToolStripSplitButton, but don't really know where to go from there. Its DropDown property is a ToolStripDropDown, but that doesn't seem to have anything regarding multiple items being selected, much less scrolling, and the text at the bottom.
So instead of the default ToolStripDropDown, I'm thinking maybe the whole drop down part should be a custom control, based on a combobox. The question then, is how to cause the right-side (drop down arrow) button to do something other than show its default drop down?
Am I on the right track here? Thanks!
Yes, I think you're on the right track. And in this case, ToolStripControlHost is your friend.
You don't necessarily need to derive from it (unless you are making your own control), but try just subscribing to the ToolStripSplitButton's DropDownOpening event:
Working example:
private ListBox listBox1;
public Form1()
{
InitializeComponent();
listBox1 = new ListBox();
listBox1.IntegralHeight = false;
listBox1.MinimumSize = new Size(120, 120); \\ <- important
listBox1.Items.Add("Item 1");
listBox1.Items.Add("Item 2");
}
private void toolStripSplitButton1_DropDownOpening(object sender, EventArgs e) {
ToolStripControlHost toolHost = new ToolStripControlHost(listBox1);
toolHost.Size = new Size(120, 120);
toolHost.Margin = new Padding(0);
ToolStripDropDown toolDrop = new ToolStripDropDown();
toolDrop.Padding = new Padding(0);
toolDrop.Items.Add(toolHost);
toolDrop.Show(this, new Point(toolStripSplitButton1.Bounds.Left,
toolStripSplitButton1.Bounds.Bottom));
}
Here is the result:
For your application, you would need to replace the ListBox with your own UserControl, so you can contain whatever your want in it. The ToolStripControlHost can only hold one control, and it's important to set the MinimumSize property, or else the dropped control isn't sized correctly.
Extra thanks to LarsTech! (I didn't know about ToolStripControlHost a few hours ago)
Here is my implementation, which is really close to the VS drop down...
You should be able to just drop this delegate & function into your Form:
public delegate void UndoRedoCallback(int count);
private void DrawDropDown(ToolStripSplitButton button, string action, IEnumerable<string> commands, UndoRedoCallback callback)
{
int width = 277;
int listHeight = 181;
int textHeight = 29;
Panel panel = new Panel()
{
Size = new Size(width, textHeight + listHeight),
Padding = new Padding(0),
Margin = new Padding(0),
BorderStyle = BorderStyle.FixedSingle,
};
Label label = new Label()
{
Size = new Size(width, textHeight),
Location = new Point(1, listHeight - 2),
TextAlign = ContentAlignment.MiddleCenter,
Text = String.Format("{0} 1 Action", action),
Padding = new Padding(0),
Margin = new Padding(0),
};
ListBox list = new ListBox()
{
Size = new Size(width, listHeight),
Location = new Point(1,1),
SelectionMode = SelectionMode.MultiSimple,
ScrollAlwaysVisible = true,
Padding = new Padding(0),
Margin = new Padding(0),
BorderStyle = BorderStyle.None,
Font = new Font(panel.Font.FontFamily, 9),
};
foreach (var item in commands) { list.Items.Add(item); }
if (list.Items.Count == 0) return;
list.SelectedIndex = 0;
ToolStripControlHost toolHost = new ToolStripControlHost(panel)
{
Size = panel.Size,
Margin = new Padding(0),
};
ToolStripDropDown toolDrop = new ToolStripDropDown()
{
Padding = new Padding(0),
};
toolDrop.Items.Add(toolHost);
panel.Controls.Add(list);
panel.Controls.Add(label);
toolDrop.Show(this, new Point(button.Bounds.Left + button.Owner.Left, button.Bounds.Bottom + button.Owner.Top));
// *Note: These will be "up values" that will exist beyond the scope of this function
int index = 1;
int lastIndex = 1;
list.Click += (sender, e) => { toolDrop.Close(); callback(index); };
list.MouseMove += (sender, e) =>
{
index = Math.Max(1, list.IndexFromPoint(e.Location) + 1);
if (lastIndex != index)
{
int topIndex = Math.Max(0, Math.Min(list.TopIndex + e.Delta, list.Items.Count - 1));
list.BeginUpdate();
list.ClearSelected();
for (int i = 0; i < index; ++i) { list.SelectedIndex = i; }
label.Text = String.Format("{0} {1} Action{2}", action, index, index == 1 ? "" : "s");
lastIndex = index;
list.EndUpdate();
list.TopIndex = topIndex;
}
};
list.Focus();
}
You can set it up and test like this, assuming you have a blank form (Form1) with a toolStrip that has 1 ToolStripSplitButton (toolStripSplitButton1) added:
public Form1()
{
InitializeComponent();
// Call DrawDropDown with:
// The clicked ToolStripSplitButton
// "Undo" as the action
// TestDropDown for the enumerable string source for the list box
// UndoCommands for the click callback
toolStripSplitButton1.DropDownOpening += (sender, e) => { DrawDropDown(
toolStripSplitButton1,
"Undo",
TestDropDown,
UndoCommands
); };
}
private IEnumerable<string> TestDropDown
{
// Provides a list of strings for testing the drop down
get { for (int i = 1; i < 1000; ++i) { yield return "test " + i; } }
}
private void UndoCommands(int count)
{
// Do something with the count when an action is clicked
Console.WriteLine("Undo: {0}", count);
}
Here is a better example using the Undo/Redo system from: http://www.codeproject.com/KB/cs/AutomatingUndoRedo.aspx
public Form1()
{
InitializeComponent();
// Call DrawDropDown with:
// The Undo ToolStripSplitButton button on the Standard tool strip
// "Undo" as the action name
// The list of UndoCommands from the UndoRedoManager
// The Undo method of the UndoRedoManager
m_TSSB_Standard_Undo.DropDownOpening += (sender, e) => { DrawDropDown(
m_TSSB_Standard_Undo,
"Undo",
UndoRedoManager.UndoCommands,
UndoRedoManager.Undo
); };
}
*Note: I did modify the Undo & Redo methods in the UndoRedoManager to accept a count:
// Based on code by Siarhei Arkhipenka (Sergey Arhipenko) (http://www.codeproject.com/KB/cs/AutomatingUndoRedo.aspx)
public static void Undo(int count)
{
AssertNoCommand();
if (CanUndo == false) return;
for (int i = 0; (i < count) && CanUndo; ++i)
{
Command command = history[currentPosition--];
foreach (IUndoRedo member in command.Keys)
{
member.OnUndo(command[member]);
}
}
OnCommandDone(CommandDoneType.Undo);
}
I'd suggest implementing the popup separately from the toolbar button. Popups are separate windows with a topmost-flag which auto-close when losing focus or pressing escape. If you code your own popup window that frees you from having to fit your behaviour to a preexisting model (which is going to be hard in your case). Just make a new topmost window with a listbox and status bar, then you are free to implement the selection behavior on the listbox like you need it.
Vs 2010 is a WPF application. If you are in the beginning of this application development than use WPF as a core technology. WPF drop down button is implemented in WPF ribbon. Source code is available on CodePlex.
I am trying to write a code in order to create dynamic textboxes.
I have Function class and have a second form in my program named ProductForm.cs
What I wanna do is to read some data with a function named GetSpecs in my Function.cs and than inside GetSpecs I want to call a function in another class and send data to my other function under ProductForm.cs class.
I am getting blank form at the end.
a part of my GetSpecs function:
private String GetSpecs(String webData)
{
......
ProductForm form2 = new ProductForm();
form2.CreateTextBox(n);
}
ProductForm.cs
public void CreateTextBox(int i)
{
ProductForm form2 = new ProductForm();
form2.Visible = true;
form2.Activate();
int x = 10;
int y = 10;
int width = 100;
int height = 20;
for (int n = 0; n < i; n++)
{
for (int row = 0; row < 4; row++)
{
String name = "txtBox_" + row.ToString();
TextBox tb = new TextBox();
tb.Name = name;
tb.Location = new Point(x, y);
tb.Height = height;
tb.Width = width + row * 2;
x += 25 + row * 2;
this.Controls.Add(tb);
}
y += 25;
}
}
I get a blank form of ProductForm. Textboxes are not created or I cannot see them.
If I put textbox inside
private void ProductForm_Load(object sender, EventArgs e)
I can see textboxes.
You're creating showing a brand new ProductForm instance (in the form2 variable), then adding controls to this (which is never shown).
You are adding the controls to the current form: this.Controls.Add(tb);, you need to add them to the other form:
form2.Controls.Add(tb);