Set and get checked boxes in MultiSelectListPreference - c#

I'm defining the MultiSelectListPreference in my axml file like this:
<MultiSelectListPreference
android:title="Title"
android:summary="Sum"
android:key="dutyMarks"
android:entries="#array/array_marks"
android:entryValues="#array/array_marksValues">
</MultiSelectListPreference>
How can check / read the checked boxes in code?
I tried to get the checked values via the PreferenceChange event:
The checked values appear there, but I have no idea how to get them...

This was also my first thought, but e.NewValue doesn't contain a public definition for 'GetEnumerator'.
We can simply cast e.NewValue from object to IEnumerable in our code, for example:
private void PreferenceChange(object sender, Preference.PreferenceChangeEventArgs e)
{
var selections = e.NewValue as IEnumerable;
if (selections != null)
{
foreach (var selection in selections)
{
Console.WriteLine(selection);
}
}
}

since e.NewValue is a HashSet, you should be able to iterate through it
foreach (string x in e.NewValue) {
// do whatever you need to do with each value x here
}

If someone stumbles across this question, here is how i solved it:
Read (the async part is pretty ugly, but I don't know how to add a 'preferenceChangeD' event)
private async void preferenceChange(object sender, Preference.PreferenceChangeEventArgs e)
{
await System.Threading.Tasks.Task.Delay(100);
List<string> sList = new List<string>();
ICollection<string> selectedValues = mslp_dutyMarks.Values;
foreach(string x in selectedValues)
sList.Add(x);
}
Write
mslp_dutyMarks.Values = new List<string> { "A", "B", "C" };

Related

ArrayList in comboBox

I need help with creating an ArrayList that adds words into a ComboBox, which then allows the user to click on the word and then it gets inserted into a RichTextBox. I do have the following code but it does not work. Hope someone could assist me please.
public partial class WordEditorApp : Form
{
//Creating an arraylist for the combobox.
ArrayList al = new ArrayList();
public WordEditorApp()
{
InitializeComponent();
//Initializing the radio buttons.
upperCase.Checked = false;
lowerCase.Checked = false;
//Adding items to the arraylist.
al.Add("Grams");
al.Add("Aristrocrats");
al.Add("Sophisticated");
al.Add("Corruption");
al.Add("Interrupt");
al.Add("Operation");
al.Add("Decision");
al.Add("Bantam");
al.Add("Brochure");
al.Add("Hydraulics");
al.Add("Properties");
//for loop to add items to the arraylist.
for (int i = 0; i < al.Count; i++)
{
comboBox1.Items.Add(al[i].ToString());
}
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
//Selected word from the combo box is appended into the textbox.
richTextBox1.AppendText(ArrayList.SelectedItem.ToString());
}
catch (Exception) { }
}
A simpler alternative
string[] al = { "Grams", "Aristrocrats", "Sophisticated", "Corruption", "Interrupt",
"Operation", "Decision", "Bantam", "Brochure", "Hydraulics", "Properties" };
comboBox1.Items.AddRange(al);
This is how I would do it:
Start by using current, efficient, type-safe and extensible objects and methods:
List<string> words = new List<string>()
{
"Grams", "Aristrocrats", "Sophisticated",
"Corruption", "Interrupt", "Operation",
"Decision", "Bantam", "Brochure", "Hydraulics", "Properties"
};
comboBox1.Items.AddRange(words.ToArray());
Then I would not append the text but set it as the SelectedText; this means the user can insert it anwhere, thus providing append, insert and replace all in one go:
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
richTextBox1.SelectedText = comboBox1.SelectedItem.ToString();
}
Adding a space after each word may also be a friendly idea..
Note that if you only want to load a fixed number of items you can do it like this as well:
comboBox1.Items.AddRange(new[] { "Grams", "Aristrocrats", "Sophisticated",
"Corruption", "Interrupt", "Operation", "Decision",
"Bantam", "Brochure", "Hydraulics", "Properties" });
Here no local list or array is needed and the type is resolved from the values.
But if you declare a List<string> at class level you can expand it with new words the user enters and later store it in a file, creating a growing word list..
I thing this is wrong:
//Selected word from the combo box is appended into the textbox.
richTextBox1.AppendText(ArrayList.SelectedItem.ToString());
^
ArrayList doesnt have a static property called SelectedItem.
Did you mean comboBox1.SelectedItem.ToString(); ?
Try the below code.
richTextBox1.AppendText(comboBox1.Text);
You are trying to append text from ArrayList..
If you insist on ArrayList class (which is deprecated):
// static: you want just one instance for all WordEditorApp instances
private static ArrayList al = new ArrayList() {
"Grams",
"Aristrocrats",
"Sophisticated",
"Corruption",
"Interrupt",
"Operation",
"Decision",
"Bantam",
"Brochure",
"Hydraulics",
"Properties"
};
...
comboBox1.Items.AddRange(al.OfType<String>());
a better design is to change ArrayList to List<String> or String[]:
private static String[] al = new String[] {
"Grams",
"Aristrocrats",
...
"Properties"
};
...
// No need in OfType<String>() here
comboBox1.Items.AddRange(al);

ComboBox searching in string, not just the first letter

I have problem making my combobox searching inside the strings in the items.
I want to narrow down a list of members. They are formatted in this way (unique member id) - First name - last name.
When i leave all the settings "as is", then it will only "allow" me to search at the first char in the string.
The DataSource is set from a list, what are made from looping through all the files in a folder. ​
The code i have been using is as follows(partial code)
private void searchForShooterComboBox_KeyUp(object sender, KeyEventArgs e)
{
//if(e => KeyCode == Keys::Down || e => KeyCode == Keys::Down)
//string comboBoxValue = searchForShooterComboBox.Text;
//searchForShooterComboBox.DataSource = null;
//searchForShooterComboBox.DataSource = fliterComboBox(searchForShooterComboBox, memberFileNames);
//searchForShooterComboBox.Text = comboBoxValue;
}
private void searchForShooterComboBox_TextChanged(object sender, EventArgs e)
{
searchForShooterComboBox.DataSource = null;
searchForShooterComboBox.DataSource = fliterComboBox(searchForShooterComboBox, memberFileNames);
}
private List<string> fliterComboBox(ComboBox cobx, List<string> stringList)
{
List<string> returnList = new List<string>();
if (cobx.Text != ""){
try
{
foreach (string s in stringList)
{
if (s.Contains(cobx.Text))
{
returnList.Add(s);
}
}
}catch{
}
}
return returnList;
}
some of the code i tried seemed to filter the list OK, but after the methods ran it fills what seems to be the first item in the new list into the "text field", so the user wont be able to continue typing a name ex.
Will it make any difference using ComboBox.Items.Add() and ComboBox.Items.Remove() instead of using DataSource?
edit: the comboBox DataSource is initially set in the form_load event handler. Where the following code regarding the combobox is:
searchForShooterComboBox.DropDownStyle = ComboBoxStyle.DropDown;
searchForShooterComboBox.AutoCompleteMode = AutoCompleteMode.Suggest;
searchForShooterComboBox.AutoCompleteSource = AutoCompleteSource.ListItems
Thanks for taking the time to look.
Okay seems i figured something out myself,don't know if its the best way, but seems to get the job done :)
firstly i added the string's into both the ComboBox.items and into a list<string>. The reason for adding them both ways is for the user to see all available options on load.
for (int i = 0; i < membersFiles.Length; i++)
{
searchForShooterComboBox.Items.Add(membersFiles[i].Replace(".txt", "").Replace(#"C:\Users\Nicolai\Desktop\skytter\", "").Replace("-", " "));
memberFileNames.Add(membersFiles[i].Replace(".txt", "").Replace(#"C:\Users\Nicolai\Desktop\skytter\", "").Replace("-", " "));
}
After that i added a combobox_keydown event from the property window.
private void searchForShooterComboBox_KeyDown(object sender, KeyEventArgs e)
{
try
{
//checking if the key pressed is RETURN, in that case try to fill the combobox with the selected item,
//and continuing with other method
if (e.KeyValue == 13)
{
searchForShooterComboBox.Text = (string)searchForShooterComboBox.SelectedItem;
fillInfoInForm();
}
//making sure the key pressed IS NOT DOWN, UP, LEFT, RIGHT arrow key.
else if (e.KeyValue > 40 || e.KeyValue < 37)
{
filterComboBox(searchForShooterComboBox, searchForShooterComboBox.Text);
searchForShooterComboBox.Select(searchForShooterComboBox.Text.Length, 0);
searchForShooterComboBox.DroppedDown = true;
}
}
catch (FileNotFoundException ex) {
MessageBox.Show("Der blev ikke fundet nogen fil med flg. sti " + ex.FileName + "\nHusk at vælge hele navnet i listen, eller skriv det nøjagtigt som det står!");
}
}
made this method to search through the list items, clear the items in the combobox, and add the ones that match.
private void filterComboBox(ComboBox cobx, string enteredSearch)
{
//clearing ComboBox items before adding the items from the LIST that meets the search
cobx.Items.Clear();
//looping over the items from the list, comparing them to the search from the combobox text field.
//if the item in the list does not contain the string searched it will return an index of -1.
for (int i = memberFileNames.Count-1; i >= 0; i--)
{
if (memberFileNames[i].IndexOf(enteredSearch, 0, StringComparison.CurrentCultureIgnoreCase) >= 0)
{
cobx.Items.Add(memberFileNames[i]);
}
}
}
if you are having trouble finding the right KeyValues, try looking at
https://msdn.microsoft.com/en-us/library/system.windows.forms.keyeventargs.keyvalue(v=vs.110).aspx
and copy paste the code from there, and add it to you key_down event handler, and it will show most info(if not all) in a message box.
That was my workaround, if you have a better way of doing it, i am all ears :)

DataGridView: sort by one type of data first

I have a DataGridView that I populate with a file and folder list. I'd like to sort the DataGridView alphabetically, but with all the folders above the files. Here's the general idea:
.\folder1\
.\folder2\
.\folder3\
.\file1
.\file2
I have a column with icons for the different filetypes, so there's a folder icon and file icons. It's the only difference I have between the two columns. Here's a picture:
So you can see that files and folders have different icons. Here is my current sort method:
private void dgvFiles_SortCompare(object sender, DataGridViewSortCompareEventArgs e) {
if(e.Column.Index == 1) {
// ???
}
else if(e.Column.Index == 4) {
string cellValue1 = e.CellValue1.ToString(),
cellValue2 = e.CellValue2.ToString();
if(!string.IsNullOrWhiteSpace(cellValue1) && !string.IsNullOrWhiteSpace(cellValue2)) {
cellValue1 = Regex.Replace(cellValue1, "[^.0-9]", "");
cellValue2 = Regex.Replace(cellValue2, "[^.0-9]", "");
int a = int.Parse(cellValue1), b = int.Parse(cellValue2);
e.SortResult = a.CompareTo(b);
e.Handled = true;
}
}
}
Is it possible to sort the DataGridView this way using a custom SortCompare method? If so, how?
I depends on how you've set the image inside the column but instead of using e.CellValue1 and e.CellValue2 as you have done for the size sorting, use GridName.Rows[e.RowIndex1] and GridName.Rows[e.RowIndex2] to access the underlying data instead.
So what I did instead was I created a class for folder items named FolderItem. I then created a list of these FolderItem objects and populated the DataGridView using the list. It actually made it really easy--I just had to use this snippet of code:
List<FolderItem> items = new List<FolderItem>();
private void dgvFiles_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) {
if(e.ColumnIndex == 1) {
items.OrderBy(i => i.type).ThenBy(i => i.oldName);
items.Reverse(); // to account for ascending/descending order
RefreshDataGridView();
}
}
public void RefreshDataGridView() {
dgvFiles.Rows.Clear();
foreach(FolderItem item in items) {
dgvFiles.Rows.Add(item.icon, item.oldName, item.newName, item.type, item.size, item.created, item.modified);
}
}
(type was null for folders so it occurred above the other items.)
You could also probably find some way to bind the datagridview to the list, but I didn't do that.

Attempting to condense my c#

I am attempting to condense my c# code because it's way too long and I feel I could use a foreach loop for my code. And you will have to excuse me if my terminology/vocabulary is incorrect, I am a Jr. programmer and still picking up the pieces.
A snippet of my code:
if (sender == LinkButtonA)
{
Session["LastNameFilter"] = "A";
}
if (sender == LinkButtonB)
{
Session["LastNameFilter"] = "B";
}
if (sender == LinkButtonC)
{
Session["LastNameFilter"] = "C";
}
if (sender == LinkButtonD)
{
Session["LastNameFilter"] = "D";
}
etc.....
Basically it is changing the filter so that I can display my "patients" in a RadGrid and filter them by their last name. But as you can see, I have to have 26 if statements just to make this work. Is their a cleaner way to do this?
You could have a dictionary mapping the buttons to the filters:
static Dictionary<Button, string> mapping = new Dictionary<Button, string>() {
{ LinkButtonA, "A" },
{ LinkButtonB, "B" },
{ LinkButtonC, "C" },
{ LinkButtonD, "D" },
};
...
Session["LastNameFilter"] = mapping[sender];
Register your buttons in a Dictionary<Button,string> :
Dictionary<Button,string> lastNameFilterByButton = new Dictionary<Button,string>()`
mapping.Add(LinkButtonA, "A");
mapping.Add(LinkButtonB, "B");
mapping.Add(LinkButtonC, "C");
mapping.Add(LinkButtonD, "D");
// ...
Session["LastNameFilter"] = lastNameFilterByButton[sender]
Set the Tag property on your buttons to the appropriate string, then set the session value to the tag:
// in the designer file
LinkButtonA.Tag = "A";
LinkButtonB.Tag = "B";
// etc.
// in the event
var btn = sender as LinkButton;
if (btn != null)
Session["LastNameFilter"] = (string)btn.Tag;
Edit: Tag is found on WinForms controls, ASP controls don't have a direct equivalent. You could probably safely use the CommandArgument property for this, though, if you're not using it for anything else (as pointed out by Jason Nesbitt).
You could also use the name of the button (Session["LastNameFilter"] = btn.Name.Substring(btn.Name.Length-1, 1);). This saves you the trouble of messing with the Tags, but means everything breaks if you change your naming convention.
What about something like
// Is sender of type Control?
Dictionary<Control, string> lookupBasedOnButton = new Dictionary<Control, string>()
{
{ LinkButtonA, "A" },
// etc
};
Session["LastNameFilter"] = lookupBasedOnButton(sender);
Depending on your needs, you might need to add error handling (e.g. check whether the item is in the dictionary, rather than throwing if it is not).
Store and fetch the value from the CommandArgument property of the LinkButton.
<asp:LinkButton runat="server" ID="LinkButtonA" CommandArgument="A" OnClick="LinkButtonA_OnClick"></asp:LinkButton>
protected void lb LinkButtonA_OnClick(object sender, EventArgs e)
{
var lb = (LinkButton) sender;
Session["LastNameFilter"] = lb.CommandArgument;
}
If you are able to add the filter value as a Command Argument to the Button then you only would need to do this (Applies to web forms LinkButton):
public void LinkButtonClicked(object sender, EventArgs e){
var linkButton = (LinkButton)sender;
Session["LastNameFilter"] = linkButton.CommandArgument;
}

value does not fall within expected range

I'm working on a windows phone project. I have a listbox with the following selectionchanged event handler:
private void judgeType_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
LoadJudgeCategories(judgeTypeListBox.SelectedItem.ToString());
}
Here is the LoadJudgeCategories method:
void LoadJudgeCategories(string judgeType)
{
string[] categories = judgeCategories[judgeType];
List<LabeledTextBox> itemSource = new List<LabeledTextBox>();
foreach (string cat in categories)
{
itemSource.Add(new LabeledTextBox(cat));
}
CategoryPanel.ItemsSource = itemSource;
}
judgeCategories is of type
Dictionary<string, string[]>
LabeledTextBox is usercontrol with a textblock and a textbox. CategoryPanel is just a listbox.
Whenever the selected item is changed, I want to clear CategoryPanel, and replace it with a new List.
Occasionally, however, when I change the selection, it gives the exception "value does not fall within the expected range".
How do I fix this?
This can happen when you add multiple controls with the same name. Try this code. Broken down with newlines for clarity. I turned it into a linq statement, and also named each of the LabeledTextBox something random.
Note: the only important thing I did was give the LabeledTextBox a name.
Random r = new Random();
void LoadJudgeCategories(string judgeType)
{
CategoryPanel.ItemsSource =
judgeCategories[judgeType]
.Select(cat =>
new LabeledTextBox(cat) { Name = r.Next().ToString() }
).ToList();
}
Just an alternative solution with ObservableCollection - there will be no need to set CategoryPanel.ItemsSource multiple times:
private ObservableCollection<LabeledTextBox> itemSource = new ObservableCollection<LabeledTextBox>();
CategoryPanel.ItemsSource = itemSource; // somewhere in the Constructor
void LoadJudgeCategories(string judgeType)
{
itemSource.Clear();
foreach (string cat in judgeCategories[judgeType])
itemSource.Add(new LabeledTextBox(cat));
}

Categories

Resources