How to get particular infomation stored in list - c#

I am using a existing web service which does a postcode search its then stored In a list box the values: "ID", "Text", "Highlight", "Cursor", "Description", "Next". I need to try and access a particular string value which is the ID & Next param and use it for validation later on. When I click on the list box I want the particular data to be taken stored then access the two pieces of information I need. How do I access the information on a particular row of the list box and use that later on?
try
{
int myMaxResultValue = (int)nud_MaxResults.Value;
int myMaxSuggestValue = (int)nud_MaxSuggestions.Value;
findResults = objBvSoapClient.CapturePlus_Interactive_Find_v2_10("Dak4-KZ62-AAdd87-X55", txt_Search.Text, txt_LastId.Text, cb_SearchFor.Text, text_Country.Text, text_LanguagePreference.Text, myMaxResultValue, myMaxSuggestValue);
if (txt_Search.Text.Length <= 2)// if less than two letters are entered nothing is displayed on the list.
{
ls_Output.Items.Clear();// Clear LstBox
ls_Output.Items.Add(String.Format(allDetails, "ID", "Text", "Highlight", "Cursor", "Description", "Next"));
MessageBox.Show("Please enter more than 2 Chars!!");
}
else if (txt_Search.Text.Length >= 3)// if greater than or equal to 3 letters in the search box continue search.
{
// Get Results and store in given array.
foreach (var items in findResults)
{ //Loop through our collection of found results and change resulting value.
ls_Output.Items.Add(String.Format(allDetails, items.Id, items.Text.ToString(), items.Highlight, items.Cursor, items.Description, items.Next));
}
}
}

As a side note your string.Format missing the variables in the string. It should be more like this
int id = 30;
string text = "Hello";
string.Format("This is the ID {0}. Here is some text {1}.", id, text);
The output will be "This is the ID 30. Here is some text Hello.".
To answer your question, you'll have to parse it to pull out the parts you want. You could use regex.split to do this. For example, if it's delimited on space you could do something like this
string[] data = Regex.Split(operation, #"\s+");
Then you can access it like this
string required = data[3];

Related

How to split C# string into variable when timestamp is optional?

I have an "id" string that I'm reading from a change feed in CosmosDB. Each record is versioned, so that whenever the record is updated, the old record will be versioned to include a timestamp, and the new record will be added.
Example:
id: productbase-001.11
GETS UPDATED
id: productbase-001.11 <- new record
id: productbase-001.11-2020-03-30 <- old record
What I want to do is get the type (productbase), then get the itemId (001.11) and get the timestamp (2020-03-30). I only need the timestamp because I want to exclude the old records from my processing logic further down.
foreach (ProcessedItem item in changes)
{
var convert = item.id.Split('-');
string itemType = convert[0];
string itemId = convert[1];
string timestamp = convert[2];
if (timestamp != null)
{
return;
}
else
{
[rest of my code]
}
}
Obviously have a problem will null refs, and also having the "-" as a delimiter will mean that I get "2020" and "03" and "30" all as separate items in the array. Also not sure how slow this will be if I have 3000 updates coming through.
If there is a better way to get these using SQL API, then I am all ears.
Use the String.Split overload that takes a count parameter
var convert = item.id.Split(new char[]{'-'}, 3);
string itemType = convert[0];
string itemId = convert[1];
string timestamp = (convert.Length == 3 ? convert[2] : null);
As we've specified a maximum of 3 items then the entire timestamp will be included as the last array item, if present.
There's a multiple ways that you could handle this. Here are a couple:
If you don't need the specific value of the timestamp, you could just check to see if convert has more than two items:
foreach (ProcessedItem item in changes)
{
var convert = item.id.Split('-');
string itemType = convert[0];
string itemId = convert[1];
if (convert.Length > 2)
{
return;
}
else
{
[rest of my code]
}
}
This is pretty non-invasive to the code that you've already written, but it wouldn't be super clear why you were doing this.
Another option would be to use a regular expression, something like:
^(?<Product>\w+)-(?<ItemNum>\d+\.\d+)-?(?<TimeStamp>\d{4}-\d{2}-\{2})?$
To me, using the named groups is very clear, but some might consider this solution to be overkill.
If it were me, I would also put all of this logic into it's own class (e.g. ProcessedItemId) or at least a static method, so that it could be reused elsewhere.

Issues with Change Password function

Having some issues with some of my code that has brought me to a brick wall. Even after searching a few hours I cant seem to get it to work. I am quite new to c# so any advice at all even if it points me in the right direction would be greatly appreciated!
What's odd is that it is correctly looping through the dataset, however when it finds the correct row.ItemArray[0].Equals(changeUserName) it does not continue the code and instead skips past it to the "Change failed" error, wont even show the messagebox!
Basically what I am trying to accomplish is this:
There is a table with 3 Columns. Username Password and Email. Password Column contains Hashed Passwords.
I have a form with 4 labels and 4 text fields:
Username - changeusername Textbox
Current Password - currentpassword Textbox
New Password - newpassword Text box
Confirm New Password - confirmnewpassword Text Box
The user fills these forms in, then hits the Change Password Button, which starts the below function:
(This function should check the value of username text box (and current password once ran through my HashPass Function) and compare them to the values in the dataset. If it finds matching values, It then should change the Password value to the new password value in newpassword Text Box. However it does not do this and I cannot figure out why!)
Note: Some of the code in //And look for matching usernames is commented out as I was just trying to get it to even show a MessageBox once it finds a matching Username. But it would not even do this!
public void changePass(string changeusername, string old, string new1, string confirmnew)
{
string EncryptedPass = HashPass(new1);
//If there is no username
if (changeusername == null)
{
MessageBox.Show("Please Enter Username!");
return;
}
//Confirm new pass must equal confirmnewpassword.
else if (new1 != confirmnew)
{
MessageBox.Show("New Passwords do not match");
}
bool loop = false;
//loop database and update new password
foreach (DataRow row in <nameremoved>stockDataSet.login)
{
//And look for matching usernames
if (row.ItemArray[0].Equals(changeUserName))
{
//row.ItemArray[1] = EncryptedPass;
MessageBox.Show("Change Success");
loop = true;
return;
}
}
//Catch Error if Failure
if (loop == false)
{
MessageBox.Show("Change Failed");
}
}
You can't change a single item inside the item array using the indexer.
This happens because when you try to access the ItemArray property, a copy of the original array is created and returned to your code.
And you change items in this copy not on the original one.
You need to get the item array returned, change it and assign it back to the ItemArray property
foreach (DataRow row in <nameremoved>stockDataSet.login)
{
//And look for matching usernames
if (row.ItemArray[0].Equals(changeUserName))
{
object[] returnedArray = row.ItemArray;
returnedArray[1] = EncryptedPass;
row.ItemArray = returnedArray;
MessageBox.Show("Change Success");
loop = true;
return;
}
}
You can check this behavior looking at the Reference Source of ItemArray
However, I can't understand why you want to use the ItemArray property in this context. You can simply refer to your row/column using the standard syntax or better use the Select method on the DataTable to find your row
DataRow[] found = login.Select($"userName = '{changeUserName}'");
if(found != null && found.Length > 0)
{
found[0]["Password"] = EncryptedPass;
}
Here I assume that your first column is named userName and you second column is named Password (change them to fit your names)

How to execute advance Listview Search

Using Windows forms, My 'listview' have multiple columns as shown in the picture.
I have been trying to make this txtbox_search to be advanced. When any character, word or number is inserted, i want Some columns of my listview to be traversed to look for the character, word, number and bring up data related to the input.
Like when i enter: txtbox_search.Text = "a"
It should travers column "Name" and fill Listview with data:
entire row that has a name which starts with "a" such as "Anwar"
entire row that has a name which starts with "a" such as "Anas"
so on with entire rows that has a name which starts with "A..."
when i enter: txtbox_search.Text = "1"
It should travers column "ID" and fill Listview with data:
entire row that has a ID which starts with "1" such as "1002"
entire row that has a ID which starts with "1" such as "1112"
so on with entire rows that has a ID which starts with "1..."
so far i have been trying this for 2 days and end up with this much:
private void textBox_DEC_Search_TextChanged(object sender, EventArgs e)
{
foreach(ListViewItem Items in listView_DEC_CustomerList.Items)
{
if(Items.Text == textBox_DEC_Search.Text)
{
listView_DEC_CustomerList.Items.Clear();
listView_DEC_CustomerList.Items.Add(Items);
}
}
if(textBox_DEC_Search.Text == "" || textBox_DEC_Search.Text == string.Empty)
{
CusList Cus = new CusList();
Cus.CustomersList(listView_DEC_CustomerList);
}
}
This code only travers first column and bring up data that matches the inserted ID, only if the Complete ID matches with txtbox_search.Text how can i make this possible? (i want it to be on client side, not from sql/database). Guides and sample code helps will be really appreciated. Thanks.
To distinguish between your 2 criteria you could use the following:
if (textBox_DEC_Search.Text.All(x => Char.IsNumber(x)))
{
Debug.WriteLine("Number");
// search through ID
}
else
{
Debug.WriteLine("Name");
// search through Name
}
It basically checks whether your input is solely numeric.
EDIT:
To check for similarity you cold use String.StartsWith of String.Contains to make the search a little more flexible
to look for the ID or NAME you need to access the subitems!
since ID is your first column check SubItems[0]
if(Items.SubItems[0].Text.StartsWith(textBox_DEC_Search.Text) ||
Items.SubItems[0]Text.Contains(textBox_DEC_Search.Text))
since NAME is your second column check SubItems[1]
if(Items.SubItems[1].Text.StartsWith(textBox_DEC_Search.Text) ||
Items.SubItems[1]Text.Contains(textBox_DEC_Search.Text))
One Problem is this line:
listView_DEC_CustomerList.Items.Clear();
because it will erase the first found result when the second is found.
So if you find 10 matches the previous 9 will be deleted!
I suggest to make first the entire search and then add the results if there are any:
private void textBox_DEC_Search_TextChanged(object sender, EventArgs e)
{
// index is 0 if numeric for ID or 1 if not for NAME
int ind = textBox_DEC_Search.Text.All(x => Char.IsNumber(x)) ? 0 : 1;
List<ListViewItem> matchlist = new List<ListViewItem>();
foreach(ListViewItem Items in listView_DEC_CustomerList.Items)
{
if(Items.SubItems[ind].Text.StartsWith(textBox_DEC_Search.Text) ||
Items.SubItems[ind]Text.Contains(textBox_DEC_Search.Text))
{
matchlist.Add(Items);
}
}
// if you have found something add the all results
if(matchlist.Any())
{
listView_DEC_CustomerList.Items.Clear();
listView_DEC_CustomerList.Items.AddRange(matchlist.ToArray());
}
}
Disclaimer: Although this solution should work I would vote to follow the advice of #RezaAghaei. It is less messy and confusing than directly manipulating the ListView
Instead of using == which looks for an exact match try one of the following (I am assuming 'Text' is the column name in the list containing the name - if not change it to Items.Name (for example)
if you want to search on 'starting with' then try
if (Items.Text.StartsWith(textBox_DEC_Search.Text.Trim())
if you want to search based on the fact that a part of the string should be looked up then try
if (Items.Text.Contains(textBox_DEC_Search.Text.Trim())
You can similarly do for any other column you would like to search on. if you want to make the search case insensitive then use .ToLower() on the string and the column name.

Acumatica Dynamic MultiSelect Dropdown

I have a screen entry to store transaction data, I want to use dynamic with multiselect combobox to select status and status data is taken from the table, but when some of the data status is selected, the amount of stored data does not match that has been selected,
I have tried the following code, but it's doesn't work for me.
public class StatusMultiStringListAttribute : PXStringListAttribute
{
public StatusMultiStringListAttribute() : base()
{
PXResultset<StatusTable> rslt = PXSelect<StatusTable>.Select(new PXGraph());
List<string> values = new List<string>();
List<string> labels = new List<string>();
foreach (PXResult<StatusTable> item in rslt)
{
BSMTStatus e = (StatusTable)item;
values.Add(e.StatusID);
labels.Add(e.Description);
}
this._AllowedValues = values.ToArray();
this._AllowedLabels = labels.ToArray();
MultiSelect = true;
}
}
is there any other solution, sorry my English is bad, thanks.
I noticed your comment on http://asiablog.acumatica.com/2016/03/multiselect-combo-box.html and saw that you posted some additional code. Based on your sample code, I identified two problems:
First of all, the values you're loading from the StatusTable DAC contain trailing spaces which are not trimmed. You haven't provided the declaration of the StatusTable DAC, but it's safe to assume from your screenshot that this field has the IsFixed attribute set to true. With these settings, the system will add white space at the end of your value. To save space in the target field, I would recommend to add a Trim() to the constructor code:
foreach (PXResult<StatusTable> item in rslt)
{
BSMTStatus e = (StatusTable)item;
values.Add(e.StatusID.Trim()); //Remove any white-space
labels.Add(e.Description);
}
Second, the status field where you're storing the selected values is not long enough to accommodate multiple selections. It's currently defined as 20 characters ([PXDBString(20, IsFixed=true)]), and even assuming you remove the whitespace you would still be limited to 4 choices. I suggest you to change it to 255, and to also remove IsFixed=true since it's not needed for this field:
[PXDBString(255)]
[PXDefault]
[PXUIField(DisplayName = "Status")]
[StatusStringList]
public virtual string Status

File input and sorting into array for further organization

I am designing a program that will take a file input, in the programs case, a census file that has 4 different inputs age, gender, marital status, and district.
My question's are
How exactly could I take the input and sort them into arrays, both integer (age and district) and string (marital status and gender) data types
How do I use them to count how many of each there are?
Any suggestions will help! I know how to read in the file and separate the info using input.Split(',') to separate whenever there is a comma, however, I am having trouble looping through so it doesn't repetitively loop unnecessarily.
You could do start doing something like this, this code uses Linq.
var records = File.ReadAllLines(filepath) // read all lines
.Select(line=> line.Split(',')) // Process each line one by one and split.
.Select(s=> new // Convert to (anonymous)object with properties.
{
Age = int.Parse(s[0]),
Gender= s[1],
MaritalStatus,= s[2],
Status= s[3],
District = int.Parse(s[4]),
}).ToList();
Now you can access each record using
foreach(var record in records)
{
// logic
Console.WriteLine(record);
}
and Count using
int count = records.Count();

Categories