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

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);
}

Related

How to avoid the overwriting in the DataBinding?

im new at programming and need help here... I want to create a Binding with a Combobox Item.
But the DataBinding is not adding a new DataBind, it overwrites the old one because of the loop. So i want if you select a "Profilname" in the Combobox that the "Path" will be displayed.
But so far, just the last loaded .txt file will be displayed because of the overwrite.
Here is now my question: How to avoid the overwrite of the DataBind in the (foreach)-loop?
For information: There is a folder which contains many .txt-files, which are all called: "profile.txt". The Programm search for all the files with a loop and then search in the files with another loop a line, which contains the word "profile_name". And then the Name has to be displayed in the ComboBox and the Path has to be binded to the "Item"/"Text" in the ComboBox.
I hope this is understandable and sorry if my code is confusing or not very strong written, im learning...
foreach (string profiletxt in Directory.EnumerateFiles(profiledirectory, "profile.txt", SearchOption.AllDirectories))
{
foreach (string line in System.IO.File.ReadAllLines(profiletxt))
{
if (line.Contains("profile_name"))
{
string remLine = line.Remove(0, 15);
string dLine = remLine.Replace("\"", "");
// dataBinding
var listProfiles = new List<Profile>() {
new Profile() {Path = profiletxt, Name = dLine,},
};
materialComboBox1.DataSource = listProfiles;
materialComboBox1.DisplayMember = "Name";
materialComboBox1.ValueMember = "Path";
}
}
if (materialComboBox1.SelectedIndex == -1)
{
MessageBox.Show("Error, couldn't find Profiles");
}
}
public class Profile
{
public string Path { get; set; }
public string Name { get; set; }
}
a ComboBox uses its ItemSource containing the available items. In your inner foreach loop you declare a new profile list for every find of profile item:
var listProfiles = new List<Profile>() {
new Profile() {Path = profiletxt, Name = dLine,},
};
materialComboBox1.DataSource = listProfiles;
Instead, you'd probably like to create a new Profile list before the first foreach loop
var listProfiles = new List<Profile>();
and in the inner loop, add your new finding to the list
listProfiles.Add(new Profile() {Path = profiletxt, Name = dLine});
Then, after the outer loop, you may assign the new ItemSource only once.
There are other newby design flaws in your code:
there should be no need to set DisplayMember and ValueMember in the .xaml.cs "code behind". Rather it belongs into the xaml code itself as these are static.
As a more general advise, consider not doing any kind of "business rules stuff" or data holding in your code behind. Rather you like to separate your UI ("View") from your data ("Model") while a "ViewModel" separates these two and implements the business rules. There are tons of good introductions on this MVVM programming pattern out there.

C# TextBox.Text = Multiple words

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))
{
...
}

Win 8.1 SearchBox SuggestionsRequested

I got an userControl that contains a searchBox.
This UserControl is inside another one.
I got a strange behavior while i'm searching, because the suggestionCollection works in a strange way.
Example :
in the searchBox i write something all works perfectly, if i choose the item it also works.
But if i try to use backspace (after the choose) i got no suggestion.
I cannot understand why it doesn't work.
That's the code
//var deferral = args.Request.GetDeferral(); //it seems to not influence the behavior
var suggestionCollection = args.Request.SearchSuggestionCollection;
try
{
TransporterExt tr_search = new TransporterExt();
//queryText is a string inserted in the searchBox
if (string.IsNullOrEmpty(queryText)) return;
tr_search.name = queryText;
suggested.Clear(); //that's a collection..
//just a search that return a collection of objects TransporterExt
querySuggestions = await TransporterService.Search_StartsWith(tr_search);
if (querySuggestions.Count > 0)
{
int i = 0;
foreach (TransporterExt tr in querySuggestions)
{
string name = tr.name;
string detail = tr.trId.ToString();
string tag = i.ToString();
string imageAlternate = "imgDesc";
suggestionCollection.AppendResultSuggestion(name, detail, tag, imgRef, imageAlternate);
this.suggested.Add(tr);
i++;
}
}
}
catch (System.ArgumentException exc)
{
//Ignore any exceptions that occur trying to find search suggestions.
Debug.WriteLine(exc.Message);
Debug.WriteLine(exc.StackTrace);
}
//deferralComplete(); //it seems to not influence the behavior
The problem is that: all the variables have the right value, but the suggestion panel appears only if i make a particular search: it appears when i change the first letter of search, or after an wrong seach
What appends when i make a search
What appends if i use the backspace, and i what i want to fix
As i said, all works perfectly, after the "backspace" action the suggestionCollection got the right value...but the panel is missing.
Could someone help me?
You can use SearchBox and SuggestionRequested event to fire the event when type on the SearchBox. I will show an Example
<SearchBox x:Name="SearchBoxSuggestions" SuggestionsRequested="SearchBoxEventsSuggestionsRequested"/>
and write the SearchBoxEventsSuggestionsRequested handler in the code behind
private void SearchBoxEventsSuggestionsRequested(object sender, SearchBoxSuggestionsRequestedEventArgs e)
{
string queryText = e.QueryText;
if (!string.IsNullOrEmpty(queryText))
{
Windows.ApplicationModel.Search.SearchSuggestionCollection suggestionCollection = e.Request.SearchSuggestionCollection;
foreach (string suggestion in SuggestionList)
{
if (suggestion.StartsWith(queryText, StringComparison.CurrentCultureIgnoreCase))
{
suggestionCollection.AppendQuerySuggestion(suggestion);
}
}
}
}
You can add the keyword to SuggestioList, and it will show in the dropdown when you type on the Searchbox.
Create the SuggestionList
public List<string> SuggestionList { get; set; }
initialize the list
SuggestionList = new List<string>();
and add keywords to the list
SuggestionList.Add("suggestion1");
SuggestionList.Add("suggestion2");
SuggestionList.Add("suggestion3");
SuggestionList.Add("suggestion4");
SuggestionList.Add("Fruits");
Thanks.

How can I check multiple textboxes if null or empty without a unique test for each?

I have about 20 text fields on a form that a user can fill out. I want to prompt the user to consider saving if they have anything typed into any of the text boxes. Right now the test for that is really long and messy:
if(string.IsNullOrEmpty(txtbxAfterPic.Text) || string.IsNullOrEmpty(txtbxBeforePic.Text) ||
string.IsNullOrEmpty(splitContainer1.Panel2) ||...//many more tests
Is there a way I could use something like an Array of any, where the array is made of the text boxes and I check it that way? What other ways might be a very convenient way in which to see if any changes have been made since the program started?
One other thing I should mention is there is a date time picker. I don't know if I need to test around that as the datetimepicker will never be null or empty.
EDIT:
I incorporated the answers into my program, but I can't seem to make it work correctly.
I set up the tests as below and keep triggering the Application.Exit() call.
//it starts out saying everything is empty
bool allfieldsempty = true;
foreach(Control c in this.Controls)
{
//checks if its a textbox, and if it is, is it null or empty
if(this.Controls.OfType<TextBox>().Any(t => string.IsNullOrEmpty(t.Text)))
{
//this means soemthing was in a box
allfieldsempty = false;
break;
}
}
if (allfieldsempty == false)
{
MessageBox.Show("Consider saving.");
}
else //this means nothings new in the form so we can close it
{
Application.Exit();
}
Why is it not finding any text in my text boxes based on the code above?
Sure -- enumerate through your controls looking for text boxes:
foreach (Control c in this.Controls)
{
if (c is TextBox)
{
TextBox textBox = c as TextBox;
if (textBox.Text == string.Empty)
{
// Text box is empty.
// You COULD store information about this textbox is it's tag.
}
}
}
Building on George's answer, but making use of some handy LINQ methods:
if(this.Controls.OfType<TextBox>().Any(t => string.IsNullOrEmpty(t.Text)))
{
//Your textbox is empty
}
public void YourFunction(object sender, EventArgs e) {
string[] txtBoxArr = { textBoxOne.Text, textBoxTwo.Text, textBoxThree.Text };
string[] lblBoxArr = { "textBoxOneLabel", "textBoxTwoLabel", "textBoxThreeLabel" };
TextBox[] arr = { textBoxOne, textBoxTwo, textBoxThree };
for (int i = 0; i < txtBoxArr.Length; i++)
{
if (string.IsNullOrWhiteSpace(txtBoxArr[i]))
{
MessageBox.Show(lblBoxArr[i] + " cannot be empty.");
arr[i].Focus();
return;
}
}
}

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);

Categories