I'm creating Windows Forms Application that creates mathematical tasks for children. I have dynamically created a list of 10 tasks represented by labels, and beside every label there is a Text Box, also dynamically created. I have one button "Confirm", for users to confirm all the answers once, but now I want to check if any of Text Box is empty, and if is I want to generate label to say "Must not be empty", keep the button "Confirm", and when user start typing that Text Box I want label to be lost, because it is no longer empty. After user populate all Text Boxes, by clicking the "Confirm" button, app continue with logic based on all inputs.
Here is the code where I check is there a empty Text Box in my User Control called UCFirstLevelAddition:
public void submitBtn_Click(object sender, EventArgs e)
{
bool thereAreEmptyContainers = logic.EmptyContainerCheck(this);
if (thereAreEmptyContainers)
{
logic.CreateEmptyContainerLabels(this);
}
else if (!thereAreEmptyContainers)
{
userAnswerList = logic.CreateUserAnswersList(this);
userAnswerListInt = logic.ConvertUserAnswerListToInt(userAnswerList);
al1AreYouShurePanel.Visible = true;
}
}
My EmptyContainerCheck() method is in another Class and looks like:
public bool EmptyContainerCheck(UCFirstLevelAddition userControl)
{
bool output=false;
foreach (Control c in userControl.Controls)
{
if (c is TextBox)
{
TextBox container = c as TextBox;
if (container.Text.Length == 0)
{
output = true;
}
}
}
return output;
}
So, when this method return true, I am doing CreateEmptyContainerLables() that looks like:
public void CreateEmptyContainerLabels(UCFirstLevelAddition userControl)
{
int x = 550, y = 180;
Label message = new Label();
foreach (Control c in userControl.Controls)
{
if (c is TextBox)
{
TextBox container = c as TextBox;
if (container.Text.Length == 0)
{
message.Text = string.Format("Ne sme biti prazno!");
message.Width = 400;
message.ForeColor = Color.Red;
message.Location = new Point(x, y + 40);
}
else { userControl.Controls.Remove(message); }
userControl.Controls.Add(message);
y = y + 60;
}
}
}
But this does not work as it should be. Can anyone give me a tip?
Thank you in advance!
Related
This question already has answers here:
Find control by name from Windows Forms controls
(3 answers)
Closed 3 years ago.
I don't want to repeat my code, so I want to make something that can change the text on multiple buttons. Is it any way you can specify what button is called and add that to the code for changing the text?
I know you can change text on a button with button1.Text = "X";
I have tried to make a string, so I only have to write the name of the button, so the calling code ends up being PickPlayer("button1");.
My full code is:
private void button9_Click(object sender, EventArgs e)
{
pickPlayer("button9");
}
private void pickPlayer(string Button)
{
if (player % 2 == 0)
{
player += 1;
Button.Text = "O";
}
else
{
player += 1;
Button.Text = "X";
}
}
But it shows an error message as follows:
string does not contain a definition for Text.
What am I doing wrong?
This will append Foo to the end of all of your buttons. Without knowing more information to what the conditions are for setting the button text, this is all I can give you.
private void Form1_Load(object sender, EventArgs e)
{
var list = GetAllButtonControls();
foreach (Control control in list)
{
if (control.GetType() == typeof(Button))
{
//Set text
control.Text += " Foo";
}
}
}
private List<Control> GetAllButtonControls()
{
List<Control> rlist = new List<Control>();
foreach (Control control in this.Controls)
{
if (control.GetType() == typeof(Button))
{
rlist.Add(control);
}
}
return rlist;
}
I have a bunch of dynamically added controls which add row by row when the user clicks the add user button. I want there to be a label when the page loads and i want the same label to move down every time the add user button is clicked (under each row of textboxes). Right now it is there on load and it moves down when the user clicks the button the first time but after that it just stays. Here is my code:
Global variables:
Label Savelbl = new Label();
int LabelX = 15;
int LabelY = 110;
int spacelbl = 15;
Page load:
Savelbl.Location = new Point(LabelX, LabelY);
Savelbl.Name = "Savelbl";
Savelbl.Text = "Please click 'save' to save your changes";
CaeUsersPanel.Controls.Add(Savelbl);
Add user button:
private void CAEAddUserbtn_Click(object sender, EventArgs e)
{
var i = UsernameTextBoxes.Count + 1; // this is a list of the added textboxes
ADDUserInfo(i); //method which adds the dynamically created textboxes
Savelbl.Location = new Point(LabelX, LabelY + spacelbl);
}
Remove user button (the label should move back up when this is clicked):
private void Remove_Click(object sender, EventArgs e)
{
DialogResult result = MessageBox.Show("Are you sure you want delete this user? \n Deleting users may break workflows", "Delete", MessageBoxButtons.YesNo);
if (result == DialogResult.Yes)
{
int idx = RemoveButtons.IndexOf((Button)sender);
// Remove button
RemoveButtons[idx].Dispose();
RemoveButtons.RemoveAt(idx);
// Remove textbox
UsernameTextBoxes[idx + 1].Dispose();
UsernameTextBoxes.RemoveAt(idx + 1);
//Shift controls up
for (int i = idx; i < RemoveButtons.Count; i++)
{
UsernameTextBoxes[i + 1].Top -= SpaceDelta;
}
space -= SpaceDelta;
Savelbl.Location = new Point(LabelX, LabelY - spacelbl);
}
}
You never update LabelX and LabelY.
LabelX = Savelbl.Location.X
LabelY = Savelbl.Location.Y
Savelbl.Location = new Point(LabelX, LabelY - spacelbl);
You could also get rid of these variables probably...
We have a DataGridView with data in a form. To enable quick search, we added TextBox to DataGridView.Controls and highlight cells which contain text from TextBox.
However, there is an issue. DataGridView consumes the Left arrow ←, Right arrow →, Home and End (with or without Shift) keys even if the cursor is in TextBox, and the user cannot change the caret position or select text from the keyboard.
TextBox generates a PreviewKeyDown event and nothing more happens.
Simplified code:
public partial class TestForm : Form
{
public TestForm()
{
InitializeComponent();
Width = 400;
Height = 400;
var txt = new TextBox { Dock = DockStyle.Bottom, BackColor = Color.Khaki };
var dgv = new DataGridView
{
Dock = DockStyle.Fill,
ColumnCount = 3,
RowCount = 5
};
dgv.Controls.Add(txt);
Controls.Add(dgv);
dgv.PreviewKeyDown += DgvOnPreviewKeyDown;
dgv.KeyDown += DgvOnKeyDown;
txt.PreviewKeyDown += TxtOnPreviewKeyDown;
txt.KeyDown += TxtOnKeyDown;
}
private void DgvOnPreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
Debug.WriteLine(String.Format("Dgv Key Preview {0}", e.KeyCode));
e.IsInputKey = true;
}
private void DgvOnKeyDown(object sender, KeyEventArgs e)
{
Debug.WriteLine(String.Format("Dgv Key {0}", e.KeyCode));
}
private void TxtOnPreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
Debug.WriteLine(String.Format("Txt Key Preview {0}", e.KeyCode));
}
private void TxtOnKeyDown(object sender, KeyEventArgs e)
{
Debug.WriteLine(String.Format("Txt Key {0}", e.KeyCode));
}
}
Type 123 in TextBox and then try the Right arrow, Left arrow, End, or Home. DataGridView change the selected cell, but the TextBox caret doesn't move.
TextBox works just fine if not inside a DataGridView (no problem at all when using the same method adding it into TreeView for example). TextBox acts similar to the Quick search Panel in the browser and has to be on top of the DataGridView. Adding a TextBox to a Form (or to be more specific, to a DataGridView parent) creates its own set of issues (tracking Location, Size, Visibility, ...) and is not acceptable.
What can be done to make sure that TextBox receive those keys and change the caret position or select text?
TextBox works just fine if not inside DataGridView (no problem at all when using the same method adding it into TreeView for example)
Apparently the problem is in DataGridView. It's because DataGridView overrides the Control.ProcessKeyPreview method:
This method is called by a child control when the child control receives a keyboard message. The child control calls this method before generating any keyboard events for the message. If this method returns true, the child control considers the message processed and does not generate any keyboard events.
The DataGridView implementation does just that - it maintains zero or one child controls internally (EditingControl), and when there is no such control active, it handles many keys (navigation, tab, enter, escape, etc.) by returning true, thus preventing the child TextBox keyboard events generation. The return value is controlled by the ProcessDataGridViewKey method.
Since the method is virtual, you can replace the DataGridView with a custom derived class which overrides the aforementioned method and prevents the undesired behavior when neither the view nor the view active editor (if any) has the keyboard focus.
Something like this:
public class CustomDataGridView : DataGridView
{
bool SuppressDataGridViewKeyProcessing => ContainsFocus && !Focused &&
(EditingControl == null || !EditingControl.ContainsFocus);
protected override bool ProcessDataGridViewKey(KeyEventArgs e)
{
if (SuppressDataGridViewKeyProcessing) return false;
return base.ProcessDataGridViewKey(e);
}
}
The above is just the half of the story and solves the cursor navigation and selection keys issue. However DataGridView intercepts another key message preprocessing infrastructure method - Control.ProcessDialogKey and handles Tab, Esc, Return, etc. keys there. So in order to prevent that, the method has to be overridden as well and redirected to the parent of the data grid view. The later needs a little reflection trickery to call a protected method, but using one time compiled delegate at least avoids the performance hit.
With that addition, the final custom class would be like this:
public class CustomDataGridView : DataGridView
{
bool SuppressDataGridViewKeyProcessing => ContainsFocus && !Focused &&
(EditingControl == null || !EditingControl.ContainsFocus);
protected override bool ProcessDataGridViewKey(KeyEventArgs e)
{
if (SuppressDataGridViewKeyProcessing) return false;
return base.ProcessDataGridViewKey(e);
}
protected override bool ProcessDialogKey(Keys keyData)
{
if (SuppressDataGridViewKeyProcessing)
{
if (Parent != null) return DefaultProcessDialogKey(Parent, keyData);
return false;
}
return base.ProcessDialogKey(keyData);
}
static readonly Func<Control, Keys, bool> DefaultProcessDialogKey =
(Func<Control, Keys, bool>)Delegate.CreateDelegate(typeof(Func<Control, Keys, bool>),
typeof(Control).GetMethod(nameof(ProcessDialogKey), BindingFlags.NonPublic | BindingFlags.Instance));
}
You can try this.
I created my own textbox and overrode method ProcessKeyMessage.
public class MyTextBox : TextBox
{
private const int WM_KEYDOWN = 0x0100;
private const int WM_SYSKEYDOWN = 0x0104;
protected override bool ProcessKeyMessage(ref Message m)
{
if (m.Msg != WM_SYSKEYDOWN && m.Msg != WM_KEYDOWN)
{
return base.ProcessKeyMessage(ref m);
}
Keys keyData = (Keys)((int)m.WParam);
switch (keyData)
{
case Keys.Left:
case Keys.Right:
case Keys.Home:
case Keys.End:
case Keys.ShiftKey:
return base.ProcessKeyEventArgs(ref m);
default:
return base.ProcessKeyMessage(ref m);
}
}
}
And then you can call:
var txt = new MyTextBox { Dock = DockStyle.Bottom, BackColor = Color.Khaki };
Try to just add the TextBox to the main form instead of the DataGridView:
Controls.Add(txt);
Controls.Add(dgv);
txt.PreviewKeyDown += DgvOnPreviewKeyDown;
txt.KeyDown += DgvOnKeyDown;
txt.PreviewKeyDown += TxtOnPreviewKeyDown;
txt.KeyDown += TxtOnKeyDown;
It sounds a bit like an exercise in futility.
It may be easier to encapsulate the behavior of both the TextBox and DataGridView controls by placing them into a UserControl together with a little code to handle events.
Here is a partial solution to the issue. TextBox still doesn't receive navigation keys input natively, but I reproduced a normal caret and selection behavior.
PreviewKeyDownEventArgs contains information about the pressed key and modifiers (Shift). For each key combination I set a new SelectionStart and SelectionLength for the TextBox.
private void TxtOnPreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
TextBox txt = (TextBox)sender;
if (e.KeyCode == Keys.Home)
{
int idx = txt.SelectionStart;
txt.SelectionStart = 0;
txt.SelectionLength = e.Shift ? idx : 0;
}
else if (e.KeyCode == Keys.End)
{
int idx = txt.SelectionStart;
if (e.Shift)
txt.SelectionLength = txt.TextLength - idx;
else
{
txt.SelectionStart = txt.TextLength;
txt.SelectionLength = 0;
}
}
else if (e.KeyCode == Keys.Left)
{
if (e.Shift)
{
if (txt.SelectionStart > 0)
{
txt.SelectionStart--;
txt.SelectionLength++;
}
}
else
{
txt.SelectionStart = Math.Max(0, txt.SelectionStart - 1);
txt.SelectionLength = 0;
}
}
else if (e.KeyCode == Keys.Right)
{
if (e.Shift)
txt.SelectionLength++;
else
{
txt.SelectionStart = Math.Min(txt.TextLength, txt.SelectionStart + 1);
txt.SelectionLength = 0;
}
}
}
I have a form on which are "listBox1" and "button1". I have two function. The second function adds checkboxes to listbox1 and the first function displays message box. But I don´t know how to write the first function.
Here I want to check which checkbox is checked and write a message:
private void button1_click(object sender, EventArgs e)
{
MessageBox.Show("radiobutton: " + rb[i].Text);
}
Here I create checkboxes: //it´s working
internal void loadSurveys()
{
WebClient client2 = new WebClient();
var json = client2.DownloadString("http://www.test.net/api/surveys/?api_key=123");
JObject data = JObject.Parse(json);
var example = JsonConvert.DeserializeObject<Example>(json);
int y = 5;
int i = 0;
RadioButton[] rb = new RadioButton[example.surveys.Length];
String chkBox_name = "";
String chkBox_text = "";
foreach (var survey in data["surveys"].Children())
{
rb[i] = new RadioButton();
rb[i].Location = new Point(5, y);
rb[i].Name = chkBox_name + survey["id"];
rb[i].Text = chkBox_text + survey["title"];
rb[i].AutoSize = true;
this.listBox1.Controls.Add(rb[i]);
y += 20;
i++;
}
}
You can go through listBox1.Controls and pick checked RadioButton
private void button1_click(object sender, EventArgs e)
{
var rb = this.listBox1.Controls.OfType<RadioButton>().SingleOrDefault(n => n.Checked);
if (rb != null)
MessageBox.Show("radiobutton: " + rb.Text);
}
since this is RadioButton there shouldn't be more then one checked
The first step, is to make the radiobutton array a variable on form level:
RadioButton[] rb
which is assigned inside loadSurveys
rb = new RadioButton[example.surveys.Length];
Then the array is accessible inside your button click
var rb = rb.FirstOrDefault(r=>r.Checked);
if(rb==null)
MessageBox.Show("No radiobutton was selected");
else
MessageBox.Show("radiobutton: " + rb[i].Text);
edit Just noticed you add the radiobuttons to a listbox. Is the listbox1 variable an actual listbox? The above will still work, but if the goal is to display a listbox of radiobuttons, you can custom paint the listbox and else use a normal panel instead of a listbox.
Either way, you can also do a firstordefault on the controls on the controls of the listbox1 variable (with OfType), but if you'd use a listbox, and fill its items, you could simply use SelectedIndexChanged
edit 2
Since I already had it, wanted to show a way to make your listbox a radiobutton box. You can make any existing listbox a radiobutton box with the following class:
public class RadioButtonBoxPainter:IDisposable
{
public readonly ListBox ListBox;
public RadioButtonBoxPainter(ListBox ListBox)
{
this.ListBox = ListBox;
ListBox.DrawMode = DrawMode.OwnerDrawFixed;
ListBox.DrawItem += ListBox_DrawItem;
}
void ListBox_DrawItem(object sender, DrawItemEventArgs e)
{
if (e.Index == -1) return;
Rectangle r = e.Bounds;
r.Width=r.Height;
bool selected= (e.State & DrawItemState.Selected) > 0;
e.DrawBackground();
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
ControlPaint.DrawRadioButton(e.Graphics, r, selected ? ButtonState.Checked : ButtonState.Normal);
r.X = r.Right + 2;
r.Width = e.Bounds.Width - r.X;
string txt;
if (ListBox.Site != null && ListBox.Site.DesignMode && e.Index >= ListBox.Items.Count)
txt = ListBox.Name;
else
txt = ListBox.GetItemText(ListBox.Items[e.Index]);
using (var b = new SolidBrush(e.ForeColor))
e.Graphics.DrawString(txt, e.Font, b, r);
if (selected)
{
r = e.Bounds;
r.Width--; r.Height--;
e.Graphics.DrawRectangle(Pens.DarkBlue, r);
}
}
public void Dispose()
{
ListBox.DrawItem -= ListBox_DrawItem;
}
}
Example of a standard implementation:
public class RadioButtonBox:ListBox
{
public readonly RadioButtonBoxPainter Painter;
public RadioButtonBox()
{
Painter = new RadioButtonBoxPainter(this);
}
[DefaultValue(DrawMode.OwnerDrawFixed)]
public override DrawMode DrawMode
{
get{return base.DrawMode;}
set{base.DrawMode = value;}
}
}
The RadioButtonBox is a control I actually use a lot. Personally I find it a lot quicker in implementing then a load of separate radiobuttons.
In case you want to use it, and want an example how to implement it in your current code, leave a comment and I'll add one.
I am creating a entry page for kiosk device using WPF. There a 3 text boxes in the page and keyboard(created using buttons). To perform the action when we press the key board button in want to display the text in the corresponding text box.
Need: How to find the currently focused text box.
code using:
void buttonElement_Click(object sender, RoutedEventArgs e)
{
// create variable for holding string
String sendString = "";
try
{
// stop all event handling
e.Handled = true;
Button btn = ((Button)sender);
// set sendstring to key
if (btn.Content.ToString().Length == 1 && btn.CommandParameter.ToString() != btn.Content.ToString())
{
sendString = btn.Content.ToString();
}
else
{
sendString = btn.CommandParameter.ToString();
}
// sendString = ((Button)sender).CommandParameter.ToString();
int position = txtAuto.SelectionStart;
// if something to send
if (!String.IsNullOrEmpty(sendString))
{
// if sending a string
if (sendString.Length > 1)
{
switch (sendString)
{
case "Del":
if (position != txtAuto.Text.Length)
{
txtAuto.Text = txtAuto.Text.Remove(position, 1);
txtAuto.SelectionStart = position;
}
break;
case "BACKSPACE":
if (position != 0)
{
txtAuto.Text = txtAuto.Text.Remove(position - 1, 1);
txtAuto.SelectionStart = position;
}
break;
case "Clear":
txtAuto.Text = string.Empty;
break;
case "ENTER":
popup.IsOpen = false;
// lbSuggestion.ItemsSource = null;
this.FetchSearchResult(txtAuto.Text.Trim());
if (lbResult.Items.Count != 0)
{
lbResult.ScrollIntoView(lbResult.Items[0]);
}
break;
}
}
else
{
txtAuto.Text = txtAuto.Text.Insert(txtAuto.SelectionStart, sendString);
txtAuto.SelectionStart = position + 1;
}
// set keyboard focus
System.Windows.Input.Keyboard.Focus(this.txtAuto);
// set normal focus
this.txtAuto.Focus();
}
}
catch (Exception)
{
// do nothing - not important for now
Console.WriteLine("Could not send key press: {0}", sendString);
}
}
This code is working fine for single textbox how to make it work for other textboxes.
Normaly the focus got lost if you click a button. So you can "save" the last focused text box in a class variable if a textbox is loosing the focus.
private TextBox _currentTextbox;
private void TextBoxLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
_currentTextbox = e.Source as TextBox;
}
attach this handler to all Text boxes and use _currentTextbox in your function.
See more at http://msdn.microsoft.com/en-us/library/aa969768.aspx
Need: How to find the currently focused text box.
You can use the FocusManager.GetFocusedElement method.
When you click the button, the button receives the focus and the textbox loses it. So, one approach would be to subscribe to the LostFocus events of all textboxes and remember which one lost the focus. The one that lost the focus last is the one that lost the focus because of the button click and hence was the one that had the focus before the click.