C# TextBox.Text = Multiple words - c#

is it possible to make more words than one, i have created a timer, which checks what is typed in a textbox, and if write password typed changes a picture, so my other if function don't work, how could i make something like this:
The code of statement, i need something like this: if (metroTextBox1.Text == "byby", "cow", "root")
if (metroTextBox1.Text == "byby")
{
Image img = Properties.Resources.Good_Pincode_48px; // Right'as
metroTextBox1.Icon = img;
}
else
{
// new wrong().Show();
Image img = Properties.Resources.Wrong_Pincode_48px; // Wrong'as
metroTextBox1.Icon = img;
}

Try this:
if(new string[] { "byby", "cow", "root" }.Contains(metroTextBox1.Text))
{
...
}
EDIT:
Like suggested in the comments you can use a HashSet instead of an Array to store the words you want to compare. The Contains method works faster with a HashSet since it has a O(1) lookup whereas Arrays and Lists have a O(n) lookup.
HashSet<string> words = new HashSet<string>(){ "byby", "cow", "root" };
if (words.Contains(metroTextBox1.Text))
{
...
}

Ok, I'll add my 2 cents to Slaven Tojić's answer:
.
You could create a property with collection of words:
private HashSet<string> WordsList { get; } = new HashSet<string>(new[]
{
"byby",
"cow",
"root"
});
.
And add event handler to TextChanged event of the TextBox:
this.textBox1.TextChanged += TextBox1OnTextChanged;
.
And in event handler use collection to check if it contains the
element:
private void TextBox1OnTextChanged(object sender, EventArgs e)
{
if (this.WordsList.Contains(textBox1.Text))
{
// ...
}
}

use this with comparater to avoid case problems
if(new string[] { "byby", "cow", "root" }
.Contains(metroTextBox1.Text,StringComparison.OrdinalIgnoreCase))
{
...
}

Related

How to get object reference dynamically by name? [duplicate]

I have a ToolStripMenuItem called myMenu. How can I access this like so:
/* Normally, I would do: */
this.myMenu... etc.
/* But how do I access it like this: */
String name = myMenu;
this.name...
This is because I am dynamically generating ToolStripMenuItems from an XML file and need to reference MenuItems by their dynamically generated names.
Use the Control.ControlCollection.Find method.
Try this:
this.Controls.Find()
string name = "the_name_you_know";
Control ctn = this.Controls[name];
ctn.Text = "Example...";
Assuming you have the menuStrip object and the menu is only one level deep, use:
ToolStripMenuItem item = menuStrip.Items
.OfType<ToolStripMenuItem>()
.SelectMany(it => it.DropDownItems.OfType<ToolStripMenuItem>())
.SingleOrDefault(n => n.Name == "MyMenu");
For deeper menu levels add more SelectMany operators in the statement.
if you want to search all menu items in the strip then use
ToolStripMenuItem item = menuStrip.Items
.Find("MyMenu",true)
.OfType<ToolStripMenuItem>()
.Single();
However, make sure each menu has a different name to avoid exception thrown by key duplicates.
To avoid exceptions you could use FirstOrDefault instead of SingleOrDefault / Single, or just return a sequence if you might have Name duplicates.
Control GetControlByName(string Name)
{
foreach(Control c in this.Controls)
if(c.Name == Name)
return c;
return null;
}
Disregard this, I reinvent wheels.
Using the same approach of Philip Wallace, we can do like this:
public Control GetControlByName(Control ParentCntl, string NameToSearch)
{
if (ParentCntl.Name == NameToSearch)
return ParentCntl;
foreach (Control ChildCntl in ParentCntl.Controls)
{
Control ResultCntl = GetControlByName(ChildCntl, NameToSearch);
if (ResultCntl != null)
return ResultCntl;
}
return null;
}
Example:
public void doSomething()
{
TextBox myTextBox = (TextBox) this.GetControlByName(this, "mytextboxname");
myTextBox.Text = "Hello!";
}
I hope it help! :)
this.Controls.Find(name, searchAllChildren) doesn't find ToolStripItem because ToolStripItem is not a Control
using SWF = System.Windows.Forms;
using NUF = NUnit.Framework;
namespace workshop.findControlTest {
[NUF.TestFixture]
public class FormTest {
[NUF.Test]public void Find_menu() {
// == prepare ==
var fileTool = new SWF.ToolStripMenuItem();
fileTool.Name = "fileTool";
fileTool.Text = "File";
var menuStrip = new SWF.MenuStrip();
menuStrip.Items.Add(fileTool);
var form = new SWF.Form();
form.Controls.Add(menuStrip);
// == execute ==
var ctrl = form.Controls.Find("fileTool", true);
// == not found! ==
NUF.Assert.That(ctrl.Length, NUF.Is.EqualTo(0));
}
}
}
One of the best way is a single row of code like this:
In this example we search all PictureBox by name in a form
PictureBox[] picSample =
(PictureBox)this.Controls.Find(PIC_SAMPLE_NAME, true);
Most important is the second paramenter of find.
if you are certain that the control name exists you can directly use it:
PictureBox picSample =
(PictureBox)this.Controls.Find(PIC_SAMPLE_NAME, true)[0];
You can use find function in your Form class. If you want to cast (Label) ,(TextView) ... etc, in this way you can use special features of objects. It will be return Label object.
(Label)this.Controls.Find(name,true)[0];
name: item name of searched item in the form
true: Search all Children boolean value
this.Controls["name"];
This is the actual code that is ran:
public virtual Control this[string key]
{
get
{
if (!string.IsNullOrEmpty(key))
{
int index = this.IndexOfKey(key);
if (this.IsValidIndex(index))
{
return this[index];
}
}
return null;
}
}
vs:
public Control[] Find(string key, bool searchAllChildren)
{
if (string.IsNullOrEmpty(key))
{
throw new ArgumentNullException("key", SR.GetString("FindKeyMayNotBeEmptyOrNull"));
}
ArrayList list = this.FindInternal(key, searchAllChildren, this, new ArrayList());
Control[] array = new Control[list.Count];
list.CopyTo(array, 0);
return array;
}
private ArrayList FindInternal(string key, bool searchAllChildren, Control.ControlCollection controlsToLookIn, ArrayList foundControls)
{
if ((controlsToLookIn == null) || (foundControls == null))
{
return null;
}
try
{
for (int i = 0; i < controlsToLookIn.Count; i++)
{
if ((controlsToLookIn[i] != null) && WindowsFormsUtils.SafeCompareStrings(controlsToLookIn[i].Name, key, true))
{
foundControls.Add(controlsToLookIn[i]);
}
}
if (!searchAllChildren)
{
return foundControls;
}
for (int j = 0; j < controlsToLookIn.Count; j++)
{
if (((controlsToLookIn[j] != null) && (controlsToLookIn[j].Controls != null)) && (controlsToLookIn[j].Controls.Count > 0))
{
foundControls = this.FindInternal(key, searchAllChildren, controlsToLookIn[j].Controls, foundControls);
}
}
}
catch (Exception exception)
{
if (ClientUtils.IsSecurityOrCriticalException(exception))
{
throw;
}
}
return foundControls;
}
Assuming you have Windows.Form Form1 as the parent form which owns the menu you've created. One of the form's attributes is named .Menu. If the menu was created programmatically, it should be the same, and it would be recognized as a menu and placed in the Menu attribute of the Form.
In this case, I had a main menu called File. A sub menu, called a MenuItem under File contained the tag Open and was named menu_File_Open. The following worked. Assuming you
// So you don't have to fully reference the objects.
using System.Windows.Forms;
// More stuff before the real code line, but irrelevant to this discussion.
MenuItem my_menuItem = (MenuItem)Form1.Menu.MenuItems["menu_File_Open"];
// Now you can do what you like with my_menuItem;
Since you're generating them dynamically, keep a map between a string and the menu item, that will allow fast retrieval.
// in class scope
private readonly Dictionary<string, ToolStripMenuItem> _menuItemsByName = new Dictionary<string, ToolStripMenuItem>();
// in your method creating items
ToolStripMenuItem createdItem = ...
_menuItemsByName.Add("<name here>", createdItem);
// to access it
ToolStripMenuItem menuItem = _menuItemsByName["<name here>"];
Have a look at the ToolStrip.Items collection. It even has a find method available.
You can do the following:
private ToolStripMenuItem getToolStripMenuItemByName(string nameParam)
{
foreach (Control ctn in this.Controls)
{
if (ctn is ToolStripMenuItem)
{
if (ctn.Name = nameParam)
{
return ctn;
}
}
}
return null;
}
A simple solution would be to iterate through the Controls list in a foreach loop. Something like this:
foreach (Control child in Controls)
{
// Code that executes for each control.
}
So now you have your iterator, child, which is of type Control. Now do what you will with that, personally I found this in a project I did a while ago in which it added an event for this control, like this:
child.MouseDown += new MouseEventHandler(dragDown);

Dynamic C# Method or multiple If-else-if blocks?

I have a situation where I need to validate if multiple checkboxes are checked in WPF application and run code block accordingly. The only thing that changes with all the iterations of the code block is the file name. Sample code looks like this
if(checkbox1.IsChecked == true)
{
Code(fileName1);
}
if(checkbox2.IsChecked == true)
{
Code(fileName2);
}
if(checkbox3.IsChecked == true)
{
Code(fileName3);
}
It all looks redundant. And I cannot create a method and pass the file name and checkBox name to it as the checkBox will be passed as a string and IsChecked property will be invalid for a string. Any way to overcome this and make the code look neat ?
If you have to manually link up the checkboxes to strings the same way you have it now, and are just looking for shorter code, you can wrap up the checkboxes into a dictionary, then loop through them:
var filesByCheckbox = new Dictionary<CheckBox, string> {
{ checkbox1, filename1 },
{ checkbox2, filename2 },
{ checkbox3, filename3 }
};
foreach (var kvp in filesByCheckbox)
{
if (kvp.Key.IsChecked)
{
Code(kvp.Value);
}
}
This doesn't really improve anything, but it just makes it a little clearer which checkbox is attached to which file so adding to the list is only one line instead of 3.
I'd probably go with Tanner's answer if it works for you.
Can you change the form to use a subclass of CheckBox? If so, you could do this:
class MyCheckBox : CheckBox
{
public string FileName { get; set; }
public void MyMethod()
{
if (IsChecked)
{
(do something with FileName);
}
}
}
Then set the value of FileName in the form designer. Finally, replace the code from your question with something like this:
checkbox1.MyMethod();
checkbox2.MyMethod();
checkbox3.MyMethod();
You need to somehow map your checkboxes to the filenames. An easy way would be to use the Tag property:
checkbox1.Tag = filename1;
checkbox2.Tag = filename2;
checkbox3.Tag = filename3;
Then put yout checkboxes into an array and process that:
var checkboxes = new [] { checkbox1, checkbox2, checkbox3 };
foreach (var checkbox in checkboxes.Where(cb => cb.IsChecked))
{
Code((string)checkbox.Tag);
}

C# Search datagridview for duplicates

Using ms visual studio and csharp .net4.
This is the code i have to check for duplicates
public void CheckForDuplicate()
{
DataGridViewRowCollection coll = ParetoGrid.Rows;
DataGridViewRowCollection colls = ParetoGrid.Rows;
List<string> listParts = new List<string>();
int count = 0;
foreach (DataGridViewRow item in coll)//379
{
foreach (DataGridViewRow items in colls)//143641
{
if (items.Cells[5].Value == item.Cells[5].Value)
{
if (items.Cells[2].Value != item.Cells[2].Value)
{
listParts.Add(items.Cells["Keycode"].Value.ToString());
count++;
dupi = true;
//txtDupe.Text = items.Cells["Keycode"].Value.ToString();
//this.Refresh();
}
}
}
}
MyErrorGrid.DataSource = listParts;
}
This is the check before it allows the user to save.
private void butSave_Click(object sender, EventArgs e)
{
CheckForDuplicate();
if (dupi == true)
{
txtDupe.Clear();
dupi = false;
}
else
{
SaveMyWorkI();
dupi = false;
}
}
This is the data that it is looking at:
Now, I know the logic must be flawed since it saving regardless.
I'm basically searching through each cell on pareto1 to see if the user has made any duplicates, if so it will not save and instead displays the part number etc in another datagridview....well that's the plan.
So could someone look through this and tell me
1) Where in my logic is this failing, also what about if the checks are correct?
2) Will the list work adding the info, if so is a simple bind to a datagrid view enough to display the results?
3) If this is just a really bad way of searching through could someone provide code that reflects what I am Trying to achieve.
Many thanks for your future comments.
UPDATE:: Ok thanks for the help, my algorithm now works, but my very last problem is displaying the part number that is duplicated on the pareto column, instead it displays the length.
public void CheckForDuplicate()
{
DataGridViewRowCollection coll = ParetoGrid.Rows;
DataGridViewRowCollection colls = ParetoGrid.Rows;
List<string> listParts = new List<string>();
int count = 0;
foreach (DataGridViewRow item in coll)//379
{
foreach (DataGridViewRow items in colls)//143641
{
count++;
if ((items.Cells[5].Value != null))
{
if ((items.Cells[5].Value != null) && (items.Cells[5].Value.Equals(item.Cells[5].Value)))
{
if ((items.Cells[2].Value != null) && !(items.Cells[2].Value.Equals(item.Cells[2].Value)))
{
listParts.Add(items.Cells["Keycode"].Value.ToString());
dupi = true;
}
}
}
}
}
MyErrorGrid.DataSource = listParts;
var message = string.Join(Environment.NewLine, listParts);
//MyErrorGrid.DataSource = message;
MessageBox.Show(message);
}
Even though the message box correctly displays the results? is it something im missing out when binding to my datagrid?
Here is a simple example showing how to perform validation during dataentry. There are various ways you can customise how the errors appear (including some sort of custom dialog to resolve errors) that might give you a better solution.
public partial class Form1 : Form
{
BindingSource bs;
DataTable dt; public Form1()
{
InitializeComponent();
BindingList<BindingClass> data = new BindingList<BindingClass>
{
new BindingClass{ Name = "one" },
new BindingClass { Name = "two"}
};
dataGridView1.DataSource = data;
dataGridView1.CellValidating += new DataGridViewCellValidatingEventHandler(dataGridView1_CellValidating);
}
void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (row.Index != e.RowIndex & !row.IsNewRow)
{
if (row.Cells[0].Value.ToString() == e.FormattedValue.ToString())
{
dataGridView1.Rows[e.RowIndex].ErrorText =
"Duplicate value not allowed";
e.Cancel = true;
return;
}
}
}
dataGridView1.Rows[e.RowIndex].ErrorText = string.Empty;
}
}
public class BindingClass
{
public string Name { get; set; }
}
}
Naturally this won't always fit your requirements of what users like to work with but I thought it could help to see another option.
You are doing comparisons with == and != .
items.Cells[5].Value exposes an object.
In your case this is most likely doing an equality check based on reference equality, which is probably not what your want. Try using something like items.Cells[5].Value.Equals(item.Cells[5].Value)
Please also consider solving such problems on the simplest abstractions available. E.g. if you had the grid bound to a collection of objects, then you could perform the cleanup operation against that collection of objects, disregarding any UI you bolt on top of it.
You can also consider using the Distinct extension method from the LINQ namespace and provide it an IEqualityComparer* to make sure the most efficient code for removing duplicates available in the .NET Framework is used by you.
*) IEqualityComparer is an abstraction that allows you to define in one place when you consider two objects to be equal. Distinct provides an overload where you can specify such a comparer.
See if this can work for you
var dup = dataGridView1.Rows.Cast<DataGridViewRow>().Distinct().Where(g => g.Index != 0);
Excluding row with index 0. It is header row.

Populating Control values from a Dictionary?

I am new to C# so please fogive my newbie question.
I created a dictionary of controls from a Windows form called dictControls. I then populated it with all text box and combobox controls and values from the form:
Dictionary<Control, string> dictFormControls = new Dictionary<Control, string>();
foreach (Control c in Controls)
{
if (c is ComboBox)
{
dictFormControls.Add(c, ((ComboBox)c).SelectedValue.ToString());
}
if (c is TextBox)
{
dictFormControls.Add(c, ((TextBox)c).Text);
}
if (c is MaskedTextBox)
{
dictFormControls.Add(c, ((MaskedTextBox)c).Text);
}
}
if (discNumber <= Convert.ToInt32(numDiscs))
{
frmAddVideo frm = new frmAddVideo(numDiscs, discNumber, videoID, sequenceID, dictFormControls);
frm.Show();
this.Close();
}
I want the dictionary basically look something like this:
Key ------------ Value
"txtName" ----- "Test"
"txtYear" ------ "1980"
I am passing this back into the same form (frmAddVideo):
public frmAddVideo(string numDiscs, int discNumber, string videoID, string sequenceID, Dictionary<Control, string> dict)
{
this.numDiscs = numDiscs;
this.discNumber = discNumber;
this.videoID = videoID;
this.sequenceID = sequenceID;
InitializeComponent();
//This is where I want to parse out the Dictionary and populate the form values
foreach (KeyValuePair<Control, string> item in dict)
{
**Basically, I am looking for a way to take **
**item(Key)**
**and do something like item(Key).Value = item(Value);**
**so it would be the same as writing**
**txtName.Text= "1980";**
**cbxLocID.Value = 1;**
}
}
I am looking for a way to take key and turn it into the control name, then add ".Text" or ".Value" to it and then set the value to item(value) as I explained in the code above.
Is this possible? I tried researching this, but I have yet to put 2 and 2 together.
You may just store the set of controls you work with in your dictionary:
class ControlBoundValueDescription
{
private Control _control;
public ControlBoundValueDescription(Control control)
{
_control = control;
}
public string Value
{
get
{
if(_control is ...) return ...
...
}
set
{
if(_control is ...) ((Xxx)_control).Yyy = value;
...
}
}
}
...
Dictionary<string, ControlBoundValueDescription> dictControls =
new Dictionary<string, ControlBoundValueDescription>();
...
// defining mappings (you may also want to populate it automatically,
// by iterating over all the controls you have on your form)
dictControls["UserName"] = new ControlBoundValueDescription(tbUserName);
dictControls["Group"] = new ControlBoundValueDescription(cbxGroup);
...
// working with controls using previously defined mappings
dictControls["UserName"].Value = "guest"; // probably, text box
dictControls["Group"].Value = "Guest Users"; // probably, combo
But the whole idea seems to be bad design. You should probably clarify the problem you're trying to solve.
If I understand your question, you can use Find()
((TextBox)myForm.Controls.Find(Key, true)).Text = Value;
((CheckBox)myForm.Controls.Find(Key, true)).Checked = Boolean.Parse(Value);

C#, variable value as a part of an object name?

For example i have a player object with a list of suits of cards it has.
player.card[0] = "diamonds";
player.card[1] = "clubs";
player.card[2] = "spades";
etc...
also i have 4 hidden pictureboxes with an image of suites ( pb_spades , pb_hearts m etc. )
and another 4 pictureboxs ( pb_playerCard1 , pb_playerCard2 , etc. ) to which I have to assign an image from a hidden pb corresponding to the suit of card the player object has.
Therefor
if ( player.card[0] == "diamonds" ) { pb_playerCard1.Image = pb_diamonds.Image; }
of course, doing it all with IFs would take quite a long time... Can I somehow use variable value as a part of an objects name?
kinda
for (int i = 1; i != 5; i++)
{
pb_playerCard+'i'.Image = pb_+'player.card[i+1]'.Image;
}
I don't think that you can use a value as a part of the control name. But, one can use an aray of controls. You will have to change many declarations and initializations of your picture boxes and put them into an array, but you will be able to write more descriptive and readable code.
Create a class Suite that has all properties, like this:
class Suite {
public string Name { get; set; }
public Image Image { get; set; }
and then create a static object for each color:
public static Diamonds = new Suite { Name = "Diamonds", Image = Resources.DiamondImage };
// ...
}
Now you can use Suite.Diamonds.
Even better is to use a Flyweight pattern to avoid the static fields. You use the Flyweight to implement the Card class.
First, there's no reason to have a hidden PictureBox control just so you can use it's Image property to store an image. Just create Image objects.
You could store the images in a dictionary, indexable by name:
var cards = new Dictionary<string, Image>() {
{ "diamonds", Image.FromFile("diamonds.jpg") }
{ "clubs", Image.FromFile("clubs.jpg") }
//...
};
Then instead of this:
if ( player.card[0] == "diamonds" ) { pb_playerCard1.Image = pb_diamonds.Image; }
You would write:
pb_playerCard1.Image = images[player.card[0]];
This code is still not great (any time you see variables like foo1, foo2, foo3, you should be putting those in an array so they can be indexed by number). The next step might be to refactor the code so you have something like:
pb_playerCard[0].Image = images[player.card[0]];
Or:
pb_playerCard[0].Image = player.card[0].Image;
thanks again guys, I got it working using a List to store card suites for the player objects and a dictionary that stores image references.
Dictionary<CardType, System.Drawing.Image> newDeckImages = new Dictionary<CardType, System.Drawing.Image>();
...
newDeckImages.Add(CardType.Diamonds, pb_diamonds.Image);
newDeckImages.Add(CardType.Hearts, pb_hearts.Image);
newDeckImages.Add(CardType.Clubs, pb_clubs.Image);
newDeckImages.Add(CardType.Spades, pb_spades.Image);
...
private void showMyCards()
{
pb_termCard1.Image = newDeckImages[Terminator.cards[0]];
pb_termCard2.Image = newDeckImages[Terminator.cards[1]];
pb_termCard3.Image = newDeckImages[Terminator.cards[2]];
pb_termCard4.Image = newDeckImages[Terminator.cards[3]];
}
The main class Player and the associated enumeration should be like this:
class Player
{
public Player(int n)
{
Cards = new List(n);
}
public IList Cards { get; private set; }
}
enum CardType
{
Diamond,
Club,
Spade,
Heart
}
Another method GetPictureBox() should in the winform partial class
public PictureBox GetPictureBox(string pictureBoxName)
{
if(this.Controls.ContainsKey(pictureBoxName))
{
Control control = this.Controls[pictureBoxName];
PictureBox pictureBox;
if ((pictureBox = control as PictureBox) != null)
{
return pictureBox;
}
}
return null;
}
Use this method in the class using the player instance.
Player player = new Player(3);
player.Cards.Add(CardType.Diamond);
player.Cards.Add(CardType.Club);
player.Cards.Add(CardType.Spade);
Dictionary dictionary = new Dictionary();
dictionary.Add(CardType.Diamond, pb_diamonds);
dictionary.Add(CardType.Spade, pb_spades);
dictionary.Add(CardType.Club, pb_clubs);
dictionary.Add(CardType.Heart, pb_hearts);
Finally the assignment to the image property,
for (int i = 1; i < 5; i++)
{
string playercardPictureBoxName = string.Concat("pb_playercard", i.ToString());
PictureBox pictureBox = this.GetPictureBox(playercardPictureBoxName);
if (pictureBox != null)
{
pictureBox.Image = dictionary[player.Cards[i - 1]].Image;
}
}
No, not how you're doing it, and although similar things can be achieved with reflection, what you want here is probably closer to just using FindControl for the "pb_playerCard" part and a simple dictionary of type Dictionary<CardSuitEnum, WhateverTheTypeOfImageIs> which you can populate with the pb_diamonds.Image etc.
Apols, I don't know what type .Image holds and can't be bothered to look it up :)

Categories