How I can control a ArrayList for duplicate value? - c#

I have a arraylist with string(codes) and I want to control whether a string is duplicate in this arraylist. if the string is duplicate i want a other code to the arraylist.
my code:
private void btn_Create_Click(object sender, EventArgs e)
{
ArrayList list = new ArrayList();
try
{
list = DoDeserialize();
}
catch (Exception ex)
{
lbl_status.Text = ex.Message;
}
string code = GetCode(7);
code = "2 - " + code;
int test = list.IndexOf(code);
txt_Code.Text = code;
lbl_status.Text = "Code wurde erstellt";
list.Add(code);
DoSerialize(list);
}

Add this in place of your list.add(code);. This method checks whether the item is already in the array list.
if(!list.Contains(code))
{
// The code does not already exist in the list, so add it
list.add(code);
} else {
// The code already exists, do something here.
}
See here for more information about the List<T>.Contains() method.

You can also use the LINQ method Distinct to remove any duplicates after you have populated your list.

Related

Im using method invoker to remove my usercontrol but when i use foreach its count was always less by 1

private void Invoke()
{
try
{
if (this.InvokeRequired)
{
this.Invoke(new MethodInvoker(delegate { Invoke(); }));
}
else
{
removeUc();
}
}
catch (Exception ex)
{
XtraMessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
this is my invoke function im using this because it came from another thread sorry im new here.
private void removeUc()
{
foreach (UserControl uc in fPanel.Controls)
{
fPanel.Controls.Remove(uc);
}
}
and this is my remove function, my problem is for example i have 3 usercontrol yet it only remove 2 it always leaves one usercontrol i want to remove all
The general rule for such situations (language-agnostic) is:
If the collection is known to be array or array-like, i.e. accessible by index, and remove shifts indices of all following items:
 → then you just iterate it backwards (with for not foreach).
If the collection is iterable but assumptions about internal data structure cannot be made:
 → then you create a list/array of elements to be removed,   then remove them in a second loop (like in apomene's answer).
private void removeUc()
{
var forRemoval = new List<UserControl>();
//Create removal list
foreach (UserControl uc in fPanel.Controls)
{
forRemoval.Add(uc);
}
//remove from fpanel
foreach (UserControl uc in forRemoval)
{
fPanel.Controls.Remove(uc);
}
}

Searching for an item within a ListBox using a TextBox and a Button

I am creating a system that includes a ListBox of integers inserted by the user. I have contained a search button and a search TextBox for the user to input the integer they want to search for within the ListBox. Once the user has inputted the integer, I want a message box to be displayed either informing the user that there is e.g. 1 integer of value '3' in the list box, or an error message box informing the user that the integer does not exist within the list box.
private void buttonSearch_Click(object sender, EventArgs e)
{
listBoxAddedIntegers.SelectedItems.Clear();
for (int i = listBoxAddedIntegers.Items.Count - 1;i>=0; i--) ;
{
if (listBoxAddedIntegers.Items[i].ToString().ToLower().Contains(textBoxSearch.Text.ToLower())) ;
{
listBoxAddedIntegers.SetSelected(i, true);
}
}
// ...
}
I am not really sure on the code that I am meant to include here, and the code that I have already inserted suggests that 'i' does not exist in the current content.
Can anyone help please?
the code that I have already inserted suggests that 'i' does not exist in the current content
As #FrankM already mentioned in the comments. You have a trailing ; after your for-loop.
for (int i = listBoxAddedIntegers.Items.Count - 1;i>=0; i--) ;
This will prevent the for-loop to execute your code within the { ... }. This can be transcribed to
for (int i = listBoxAddedIntegers.Items.Count - 1;i>=0; i--)
{
// Do nothing.
}
{
// now your code
}
This means also that your code within the last curly braces will be in its own scope and so that all your defined variables will be unavailable to the following code.
Answering your actual question:
As you already do for selecting the matching items. You can extent this looping by counting up a counter. And later on show the results with a MessageBox.
With the following snippet of your code
listBoxAddedIntegers.Items[i].ToString().ToLower().Contains(textBoxSearch.Text.ToLower()))
you are currently checking if an item of your list contains the entered TextBox.Text.
So if the user has entered 3, 4, 5, ..., 13, 23 in the ListBox and searches for 3. He will get 3 matches. If you want only 1 match you should use String.Equals(). I used StringComparison.InvariantCultureIgnoreCase to avoid calling ToLower().
private void buttonSearch_Click(object sender, EventArgs e)
{
var counter = 0;
for (int i = 0; i < this.listBoxAddedIntegers.Items.Count; i++)
{
var item = this.listBoxAddedIntegers.Items[i];
if (string.Equals(item.ToString(), this.textBoxSearch.Text, StringComparison.InvariantCultureIgnoreCase))
{
this.listBoxAddedIntegers.SelectedItems.Add(item);
counter++;
}
}
if (counter == 0)
{
MessageBox.Show($"No matches for \"{this.textBoxSearch.Text}\" found!", "Search Results",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
MessageBox.Show($"{counter} items found for \"{this.textBoxSearch.Text}\"!", "Search Results",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
Hint:
Since C#6 you can use string interpolation instead of String.Format() or string concatenation (+).
private void buttonSearch_Click(object sender, EventArgs e)
{
listBoxAddedIntegers.SelectedItems.Clear();
var itemsFound = listBoxAddedIntegers.Items.Where(i=>i.ToString().ToLower().Contains(textBoxSearch.Text.ToLower())).ToList();
if(itemsFound == null)
{
MessageBox.Show("No matches found.");
}
else
{
MessageBox.Show("Found " + itemsFound.Count + " matches.");
}
}
You have to do this:
int count=0;
for(int i=0;i<listBoxAddedIntegers.Items.Count;i++)
{
if(listBoxAddedIntegers.Items[i].Items[i].ToString().ToLower().Contains(textBoxSearch.Text.ToLower())
{
count+=1;
}
}
if(count>0)
{
//display your message here after the loop with the count
}
else
{
//display your message with error
}

Delete files displayed in a listbox in c#?

I have a listbox which displays the results of a file search in Windows.
What I'd like to be able to do is press the delete key whilst the item/s is highlighted and have the actual file deleted from the system.
I have it working for directories with Directory.Delete(obj.ToString()); but I can't get the following to work for files, if someone could help it would be appreciated. I get an illegal characters error after I press the Del key.
private void listBoxResults_KeyDown(object sender, KeyEventArgs e)
{
if (btnFilesClicked == true)
{
if (e.KeyCode == Keys.Delete)
{
List<int> sItems = new List<int>();
foreach (var obj in listBoxResults.SelectedIndices)
{
sItems.Add(Convert.ToInt32(obj));
}
foreach (var obj in listBoxResults.SelectedItems)
{
try
{
File.Delete(obj.ToString());
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
foreach (int item in sItems.OrderByDescending(x => x))
{
listBoxResults.Items.RemoveAt(item);
}
}
}
First of all ListBox.SelectedItems Is an instance of IList which is not a generic implementation so it would give you only object instance...!
Have a look at this msdn link for ListBox.SelectedItems
Second thing When you will invoke ToString() on obj it's default implementation would return you type name.
This is the reason your code is not working exactly how you wanted.
try
{
File.Delete(obj.ToString()); // this requires file name not the type name
}
You need to some how get the fileName first and then you can call Delete method like below.
try
{
var fileName = GetFileName();
File.Delete(fileName);
}

Issues with ListView & File Output

I have so many issues with my project, i really don't know where to begin. First off, i get an error "an object reference is required for non-static field, method or property". It underlines retPath (the line: DriveRecursion_results.DriveRecursion(retPath);). I have no idea how to fix this.
THe other thing i'm still stumped on is how to populate a listview on my Windows Form. What i want is a list of files that need to be renamed (versus a list of all files in my list.)
Can anybody help? I have been struggling miserably with this for several hours now.
Here is my code:
Form1.cs:
namespace FileMigration
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
FolderSelect("Please select:");
}
public string FolderSelect(string txtPrompt)
{
//Value to be returned
string result = string.Empty;
//Now, we want to use the path information to population our folder selection initial location
string initialCheckoutPathDir = (#"C:\");
System.IO.DirectoryInfo info = new System.IO.DirectoryInfo(initialCheckoutPathDir);
FolderBrowserDialog FolderSelect = new FolderBrowserDialog();
FolderSelect.SelectedPath = info.FullName;
FolderSelect.Description = txtPrompt;
FolderSelect.ShowNewFolderButton = true;
if (FolderSelect.ShowDialog() == DialogResult.OK)
{
string retPath = FolderSelect.SelectedPath;
if (retPath == null)
{
retPath = "";
}
DriveRecursion_Results ds = new DriveRecursion_Results();
ds(retPath);
result = retPath;
//Close this form.
}
return result;
}
}
}
Here is DriveRecursion_Results.cs:
namespace FileMigration
{
public partial class DriveRecursion_Results : Form
{
public DriveRecursion_Results()
{
InitializeComponent();
}
private void fileOutput_SelectedIndexChanged(object sender, EventArgs e)
{
}
public void DriveRecursion(string retPath)
{
// string[] files = Directory.GetFiles(retPath, "*.*", SearchOption.AllDirectories);
string pattern = " *[\\~#%&*{}/<>?|\"-]+ *";
string replacement = "";
Regex regEx = new Regex(pattern);
string[] fileDrive = Directory.GetFiles(retPath, "*.*", SearchOption.AllDirectories);
List<string> filePath = new List<string>();
foreach (string fileNames in fileDrive)
{
if (regEx.IsMatch(fileNames))
{
filePath.Add(fileNames);
//I tried adding my listview (fileOptions) here but I cannot for some reason
}
}
}
}
}
ANY help would really be appreciated :( Does anybody have any ideas on how to change my code so it actually works?
Issue 1: your function is static. If it stops being such, this will work. This is because a static function does not have this hidden 'this' argument - the reference to object it acts upon. So, it can only access static data members, not regular ones.
You can't add the items to your listview from that level because the listview is non-static and the method DriveRecursion is static. I would start by changing the DriveRecursion method to be non-static or return a list of file paths.
You are not able to add items to your list view because you are trying to add them from a static method.
Since it is static there is no ListView because there isn't actually a Form to add things to. You will need to make DriveRecursion() not static in order to add things to the ListView.
Additionally, when you make DriveRecursion() not static, you will need a way to let Form1 know which DriveRecursion_Results class to populate.
Another approach you could take is having Form1 return retPath to DriveRecursion_Results.
Edit
Removed irrelevant parts of my original answer
I have copied your code exactly how you posted it. And then made the following changes to FolderSelect() in Form1.cs When I run this code. I can get the second window to pop up, but not the other window to close, because that will cause the application to quit.
Please make sure you have ds.Show() and do at some point call ds.DriveRecursion(retPath)
Modified FolderSelect(string) in Form1.cs:
private void FolderSelect( string txtPrompt )
{
//Value to be returned
string result = string.Empty;
//Now, we want to use the path information to population our folder selection initial location
string initialCheckoutPathDir = ( "C:\\" );
System.IO.DirectoryInfo info = new System.IO.DirectoryInfo( initialCheckoutPathDir );
FolderBrowserDialog FolderSelect = new FolderBrowserDialog();
FolderSelect.SelectedPath = info.FullName;
FolderSelect.Description = txtPrompt;
FolderSelect.ShowNewFolderButton = true;
if( FolderSelect.ShowDialog() == DialogResult.OK )
{
string retPath = FolderSelect.SelectedPath;
if( retPath == null )
{
retPath = "";
}
DriveRecursion_Results ds = new DriveRecursion_Results();
ds.DriveRecursion( retPath );
ds.Show();
result = retPath;
//Close this form.
}
return;
}

Google Suggestish text box (autocomplete)

What would be the best way to develop a text box that remembers the last x number of entries that were put into it. This is a standalone app written with C#.
This is actually fairly easy, especially in terms of showing the "AutoComplete" part of it. In terms of remembering the last x number of entries, you are just going to have to decide on a particular event (or events) that you consider as an entry being completed and write that entry off to a list... an AutoCompleteStringCollection to be precise.
The TextBox class has the 3 following properties that you will need:
AutoCompleteCustomSource
AutoCompleteMode
AutoCompleteSource
Set AutoCompleteMode to SuggestAppend and AutoCompleteSource to CustomSource.
Then at runtime, every time a new entry is made, use the Add() method of AutoCompleteStringCollection to add that entry to the list (and pop off any old ones if you want). You can actually do this operation directly on the AutoCompleteCustomSource property of the TextBox as long as you've already initialized it.
Now, every time you type in the TextBox it will suggest previous entries :)
See this article for a more complete example: http://www.c-sharpcorner.com/UploadFile/mahesh/AutoCompletion02012006113508AM/AutoCompletion.aspx
AutoComplete also has some built in features like FileSystem and URLs (though it only does stuff that was typed into IE...)
#Ethan
I forgot about the fact that you would want to save that so it wasn't a per session only thing :P But yes, you are completely correct.
This is easily done, especially since it's just basic strings, just write out the contents of AutoCompleteCustomSource from the TextBox to a text file, on separate lines.
I had a few minutes, so I wrote up a complete code example...I would've before as I always try to show code, but didn't have time. Anyway, here's the whole thing (minus the designer code).
namespace AutoComplete
{
public partial class Main : Form
{
//so you don't have to address "txtMain.AutoCompleteCustomSource" every time
AutoCompleteStringCollection acsc;
public Main()
{
InitializeComponent();
//Set to use a Custom source
txtMain.AutoCompleteSource = AutoCompleteSource.CustomSource;
//Set to show drop down *and* append current suggestion to end
txtMain.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
//Init string collection.
acsc = new AutoCompleteStringCollection();
//Set txtMain's AutoComplete Source to acsc
txtMain.AutoCompleteCustomSource = acsc;
}
private void txtMain_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
//Only keep 10 AutoComplete strings
if (acsc.Count < 10)
{
//Add to collection
acsc.Add(txtMain.Text);
}
else
{
//remove oldest
acsc.RemoveAt(0);
//Add to collection
acsc.Add(txtMain.Text);
}
}
}
private void Main_FormClosed(object sender, FormClosedEventArgs e)
{
//open stream to AutoComplete save file
StreamWriter sw = new StreamWriter("AutoComplete.acs");
//Write AutoCompleteStringCollection to stream
foreach (string s in acsc)
sw.WriteLine(s);
//Flush to file
sw.Flush();
//Clean up
sw.Close();
sw.Dispose();
}
private void Main_Load(object sender, EventArgs e)
{
//open stream to AutoComplete save file
StreamReader sr = new StreamReader("AutoComplete.acs");
//initial read
string line = sr.ReadLine();
//loop until end
while (line != null)
{
//add to AutoCompleteStringCollection
acsc.Add(line);
//read again
line = sr.ReadLine();
}
//Clean up
sr.Close();
sr.Dispose();
}
}
}
This code will work exactly as is, you just need to create the GUI with a TextBox named txtMain and hook up the KeyDown, Closed and Load events to the TextBox and Main form.
Also note that, for this example and to make it simple, I just chose to detect the Enter key being pressed as my trigger to save the string to the collection. There is probably more/different events that would be better, depending on your needs.
Also, the model used for populating the collection is not very "smart." It simply deletes the oldest string when the collection gets to the limit of 10. This is likely not ideal, but works for the example. You would probably want some sort of rating system (especially if you really want it to be Google-ish)
A final note, the suggestions will actually show up in the order they are in the collection. If for some reason you want them to show up differently, just sort the list however you like.
Hope that helps!
I store the completion list in the registry.
The code I use is below. It's reusable, in three steps:
replace the namespace and classname in this code with whatever you use.
Call the FillFormFromRegistry() on the Form's Load event, and call SaveFormToRegistry on the Closing event.
compile this into your project.
You need to decorate the assembly with two attributes: [assembly: AssemblyProduct("...")] and [assembly: AssemblyCompany("...")] . (These attributes are normally set automatically in projects created within Visual Studio, so I don't count this as a step.)
Managing state this way is totally automatic and transparent to the user.
You can use the same pattern to store any sort of state for your WPF or WinForms app. Like state of textboxes, checkboxes, dropdowns. Also you can store/restore the size of the window - really handy - the next time the user runs the app, it opens in the same place, and with the same size, as when they closed it. You can store the number of times an app has been run. Lots of possibilities.
namespace Ionic.ExampleCode
{
public partial class NameOfYourForm
{
private void SaveFormToRegistry()
{
if (AppCuKey != null)
{
// the completion list
var converted = _completions.ToList().ConvertAll(x => x.XmlEscapeIexcl());
string completionString = String.Join("¡", converted.ToArray());
AppCuKey.SetValue(_rvn_Completions, completionString);
}
}
private void FillFormFromRegistry()
{
if (!stateLoaded)
{
if (AppCuKey != null)
{
// get the MRU list of .... whatever
_completions = new System.Windows.Forms.AutoCompleteStringCollection();
string c = (string)AppCuKey.GetValue(_rvn_Completions, "");
if (!String.IsNullOrEmpty(c))
{
string[] items = c.Split('¡');
if (items != null && items.Length > 0)
{
//_completions.AddRange(items);
foreach (string item in items)
_completions.Add(item.XmlUnescapeIexcl());
}
}
// Can also store/retrieve items in the registry for
// - textbox contents
// - checkbox state
// - splitter state
// - and so on
//
stateLoaded = true;
}
}
}
private Microsoft.Win32.RegistryKey AppCuKey
{
get
{
if (_appCuKey == null)
{
_appCuKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(AppRegistryPath, true);
if (_appCuKey == null)
_appCuKey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(AppRegistryPath);
}
return _appCuKey;
}
set { _appCuKey = null; }
}
private string _appRegistryPath;
private string AppRegistryPath
{
get
{
if (_appRegistryPath == null)
{
// Use a registry path that depends on the assembly attributes,
// that are presumed to be elsewhere. Example:
//
// [assembly: AssemblyCompany("Dino Chiesa")]
// [assembly: AssemblyProduct("XPathVisualizer")]
var a = System.Reflection.Assembly.GetExecutingAssembly();
object[] attr = a.GetCustomAttributes(typeof(System.Reflection.AssemblyProductAttribute), true);
var p = attr[0] as System.Reflection.AssemblyProductAttribute;
attr = a.GetCustomAttributes(typeof(System.Reflection.AssemblyCompanyAttribute), true);
var c = attr[0] as System.Reflection.AssemblyCompanyAttribute;
_appRegistryPath = String.Format("Software\\{0}\\{1}",
p.Product, c.Company);
}
return _appRegistryPath;
}
}
private Microsoft.Win32.RegistryKey _appCuKey;
private string _rvn_Completions = "Completions";
private readonly int _MaxMruListSize = 14;
private System.Windows.Forms.AutoCompleteStringCollection _completions;
private bool stateLoaded;
}
public static class Extensions
{
public static string XmlEscapeIexcl(this String s)
{
while (s.Contains("¡"))
{
s = s.Replace("¡", "¡");
}
return s;
}
public static string XmlUnescapeIexcl(this String s)
{
while (s.Contains("¡"))
{
s = s.Replace("¡", "¡");
}
return s;
}
public static List<String> ToList(this System.Windows.Forms.AutoCompleteStringCollection coll)
{
var list = new List<String>();
foreach (string item in coll)
{
list.Add(item);
}
return list;
}
}
}
Some people shy away from using the Registry for storing state, but I find it's really easy and convenient. If you like, You can very easily build an installer that removes all the registry keys on uninstall.

Categories

Resources