I have a Windows.Forms.ListView where the user shall be able to add and remove entries. Particularly, those are files (with attributes) the user can pick through a dialog. Now, I want to check whether the file names / entries I get from the file picker are already in the list; in other words, there shall only be unique items in the ListView.
I could not find any way to compare ListViewItems to check whether the exact same entry and information is already present in my ListView. The only way I see now is to:
> Loop through the files I get from the picker (multiselect is true)
> Loop through ListView.Items
compare ListViewItem.Text
> Loop through ListViewItem.SubItems
compare .Text
If during the comparisons a complete match was found, the new entry is a duplicate and thus is not added afterwards.
This seems like an awful lot of effort to do something that I would find to be a function that is not so uncommon. Is there any other way to achieve this?
The file system itself uses only the filename to test for uniqueness, so you should do the same, no need to compare sub-items too.
Items in a ListView typically represent some object. What I usually do is to assign that object (or at least some value identifying the object) to the Tag property of the corresponding ListViewItem when they are added to the list. That way you get a quite simple setup where you can compare items by getting the values from the Tag property and perform the comparison on those objects instead of the list view representation of them.
Related
So I have a SP list with about 100k items (voucher codes) in it.
Each of them has columns for State (Active/Used), Value (10,20,30) Group (Normal, Special) and Code (random alphanumeric). Each of the columns are indexed
I can't use CAML to get the next active code for a certain group and value, because each of the criteria would return > 5k items (list view threshold).
So what would be the most efficient way to retrieve the next code?
As the list is continuously growing, loading all items with SPListItemCollectionPosition is not really an option. Isn't there a better way?
It should work for onprem, as well as spOnline
Thank you
If your Code is a progressive number, increasing at any new entered item, you have 2 options:
Create a service List that you can name something like CodeCounter, here you store the last created Code in a column. Create a workflow in main list, starting at item creation. This workflow will read the last created Code from service list, then update it to Code+1 and in parallel manages the update (optional) of main code in main list
use an event handler (farm solution, here the query surely works better)
I have a situation wherein a List object is built off of values pulled from a MSSQL database. However, this particular table is mysteriously getting an errant record or two tossed in. Removing the records cause trouble even though they have no referential links to any other tables, and will still get recreated without any known user actions taken. This causes some trouble as it puts unwanted values on display that add a little bit of confusion. The specific issue is that this is a platform that allows users to run a search for quotes, and the filtering allows for sales rep selection. The select/dropdown field is showing these errant values, and they need to be removed.
Given that deleting the offending table rows does not provide a desirable result, I was thinking that maybe the best course of action was to modify the code where the List object is created and either filter the values out or remove them after the object is populated. I'd like to do this in a clean, scalible fashion by providing some kind of appendable data object where I could just add in a new string value if something else cropped up as opposed to doing something clunky that adds new code to find the value and remove it each time.
My thought was to create a string array, and somehow loop through that to remove bad List values, but I wasn't entirely certain that was the best way to approach this, and I could not for the life of me think of a clean approach for this. I would think that the best way would be to add a filter within the Find arguments, but I don't know how to add in an array or list that way. Otherwise I figured to loop through the values either before or after the sorting of the List and remove any matches that way, but I wasn't sure that was the best choice of actions.
I have attached the current code, and would appreciate any suggestions.
int licenseeID = Helper.GetLicenseeIdByLicenseeShortName(Membership.ApplicationName);
List<User> listUsers;
if (Roles.IsUserInRole("Admin"))
{
//get all users
listUsers = User.Find(x => x.LicenseeID == licenseeID).ToList();
}
else
{
//get only the current user
listUsers = User.Find(x => (x.LicenseeID == licenseeID && x.EmailAddress == Membership.GetUser().Email)).ToList();
}
listUsers.Sort((x, y) => string.Compare(x.FirstName, y.FirstName));
-- EDIT --
I neglected to mention that I did not develop this, I merely inherited its maintenance after the original developer(s) disappeared, and my coworker who was assigned to it left the company. I'm not really really skilled at handling ASP.NET sites. Many object sources are hidden and unavailable for edit, I assume due to them being defined in a DLL somewhere. So, for any of these objects that are sourced from database tables, altering the tables will not help, since I would not be able to get the new data anyway.
However, I did try to do the following to filter out the undersirable data:
List<String> exclude = new List<String>(new String[] { "value1" , "value2" });
listUsers = User.Find(x => x.LicenseeID == licenseeID && !exclude.Contains(x.FirstName)).ToList();
Unfortunately it only resulted in an error being displayed to the page.
-- EDIT #2 --
I got the server setup to accept a new event viewer source so I could write info to the Application log to see what was happening. Looks like this installation of ASP.NET does not accept "Contains" as an action on a List object. An error gets kicked out stating that the method is not available.
I will probably add a bit to the table and flag Errant rows and then skip them when I query the table, something like
&& !ErrantData
Other way, that requires a bit more upkeep but doesn't require db change, would be to keep a text file that gets periodically updated and you read it and remove users from list based on it.
The bigger issue is unknown rows creeping in your database. Changing user credentials and adding creation timestamps may help you narrow down the search scope.
So I have an arraylist that will display data to a listbox. Then, the user can select an entry in the listbox. From there, I need to be able to grab whatever entry they select. I'm using VS 2010.
I have been trying
tempArray.Insert(0, myarray.IndexOf(mylistbox.SelectedIndex);
All this is doing is giving me the actual index number and not the contents of the index. I'm not sure how to index the arraylist to get the object that is contained at that index.
And yes, I know that I should be using List objects, but it is for class and we have yet to be taught list objects.
As the name suggests .IndexOf() will return an index from the array.
Array.IndexOf Method
This is obviously not what you want.
What you should look at is using the SelectedItem instead of the SelectedIndex.
That way, you can access the object directly and insert it into your list. One thing to remember is that SelectedItem will return an Object. This means that it will have to be cast to the type that you expect to be using.
Also, are you wanting to constantly insert items to the top of the list or does it not matter. If you can append it to the end of the list, try using .Add(yourObject).
If these are actual arrays you are working with, shouldn't you be able to to access what's in the array by using the [ ] syntax? i.e.
myArray[myListBox.SelectedIndex]
1) Dont use ArrayList... that's an old class. Use List<T> instead.
2) Have you tried ListBox.SelectedItem ? That seems a bit simpler...
I just came accross this table:
Please let me know what difference in poor-->better for the last 5 items.
The reason for all of this is quite simple. When you write SPList.Items.Count to get the total number of items, SPList.Items returns the collection of all items in the list.
You don't want the all items, this can be an expensive action.
By writing SPList.ItemCount, you make sure you only read a number from the database, and not all items.
Essentially, this is true for all items in the list - you should generally avoid using the entire Collection objects (i.e. SPList.Items or SPFolder.Files) when you can. Similarly, if you use them more than once, you should cache them using a local variable.
Here's an example using indexers. Suppose I have a Guid, and want to get an item.
SPListItem item = list.Items[guid];
Looks innocent enough, but it is actually the same as:
SPListItemCollection items = list.Items;
SPListItem item = items[guid];
The point is - SharePoint (and C#, really) doesn't know what you're going to do next, or how you're going to use the collection. The moment you've wrote .Items you already made a slow operation.
he reason for all of this is quite simple. When you write SPList.Items.Count to get the total number of items, SPList.Items returns the collection of all items in the list.
You don't want the all items, this can be an expensive action.
By writing SPList.ItemCount, you make sure you only read a number from the database, and not all items.
Essentially, this is true for all items in the list - you should generally avoid using the entire Collection objects (i.e. SPList.Items or SPFolder.Files) when you can. Similarly, if you use them more than once, you should cache them using a local variable.
Here's an example using indexers. Suppose I have a Guid, and want to get an item.
SPListItem item = list.Items[guid];
Looks innocent enough, but it is actually the same as:
SPListItemCollection items = list.Items;
SPListItem item = items[guid];
The point is - SharePoint (and C#, really) doesn't know what you're going to do next, or how you're going to use the collection. The moment you've wrote .Items you already made a slow operation.
Currently, I'm populating a drop down list when a file is created in a configurable folder.
if (!downloadRspDropDown.Items.Contains(new ListItem(txt, fileData.FullName))
Then, I add the file and remove "No Responses Available".
However, if the same file is resubmitted (i.e., the file name is the same but the timestamp is different), then I want to remove the older entry and replace it with a new entry in the drop down list.
I have the filename, so I go into the "else" block from the line of code above. From there, I'm checking to see if I have the same filename and a different creation time.
if (downloadRspDropDown.Items.Contains(new ListItem(txt, fileData.FullName) &&
downloadRspDropDown.Items.Contains(new ListItem(txt, fileData.CreationTime)
From here, I want to find the position, remove it, and add the new text. This approach isn't working. Can anyone offer an alternate approach?
I dont know if that is your current problem, but this line is definitly causing trouble:
if (!downloadRspDropDown.Items.Contains(new ListItem(txt, fileData.FullName))
What you probably want to achieve is a check for equality based on a value. But this line of code performs an equality check based on a reference and can't be true, because you create a new ListItem that definitly has another reference than the item already added to the Dropdownlist.
Try to use the .FindByValue method instead.
Edit based on comment:
Try something like this:
ListItem _li = downloadRspDropDown.Items.FindByValue(fileData.FullName);
if(_li != null)
{
downloadRspDropDown.Items.Remove(_li);
}