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);
}
Related
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);
}
}
I already have the saving part down and I know it works, but when I click load button, it will not display anything that I have saved from the text boxes that go to the saying.txt file
using System;
using System.IO;
using System.Windows.Forms;
namespace WindowsFormsApplication2
{
public partial class Grades : Form
{
private StreamWriter fil;
public Grades()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
try
{
fil = new StreamWriter("saying.txt"); //This is the txt file
}
catch (DirectoryNotFoundException exc)
{
lstBxDisplay.Text = "Nothing " +
exc.Message;
}
catch (System.IO.IOException exc)
{
lstBxDisplay.Text = exc.Message;
}
}
// saving the files to the saying.txt
private void btnSaveAs_Click(object sender, EventArgs e)
{
try
{
fil.WriteLine(txtBxLastName.Text);
txtBxLastName.Text = "";
txtBxLastName.Focus();
}
catch (System.IO.IOException exc)
{
lstBxDisplay.Text = exc.Message;
}
}
// next is the load button to load the files into the list/display box
private void btnLoad_Click(object sender, EventArgs e)
{
string inValue;
try
{
using (StreamReader infil =
new StreamReader("saying.txt"))
{
inValue = infil.ReadLine();
while (inValue != null)
{
inValue = infil.ReadLine();
if (inValue != null)
this.lstBxDisplay.Items.Add(inValue);
} // end of while
} // end of using
}
catch (System.IO.IOException exc)
{
lstBxDisplay.Text = exc.Message;
}
}
private void Grades_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
fil.Close();
}
catch
{
}
}
}
}
any reason why it is not loading into the list box? I have tried both label and text box to display the message and neither of them work. I debugged the program and it is executing fine
You have multiple issues here but I will point out two main issues that will get your code working.
You are not closing the stream when you try to save. If the stream stays open, you will never be able to read the values when you try to "Load" the file. You need to call fil.Close(); at the end of your btnSaveAs_Click method.
This is how the save should read.
fil.WriteLine(txtBxLastName.Text);
txtBxLastName.Text = "";
txtBxLastName.Focus();
fil.Close();
You're skipping the first line of the file in your "Load" method. You call infil.ReadLine(); then in the loop, you call it again before you add it to your listbox. You need to move your second ReadLine(). If you are only ever writing a single line to the file, your existing code will skip that first line and try to read it again which will be null (no second line). So, it will never add anything to your listbox.
This is how the reads should be ordered.
using (StreamReader infil = new StreamReader("saying.txt"))
{
inValue = infil.ReadLine();
while (inValue != null)
{
this.lstBxDisplay.Items.Add(inValue);
inValue = infil.ReadLine();
} // end of while
} // end of using
Those changes will get you working. Now to point out, you are going about reading and writing to a file all wrong. You should not be opening a stream in your form load and waiting for button clicks to be writing/reading from that stream. Unless you have a very good reason to do what you are doing, you should be opening your stream, performing the read/write operation, and closing your stream right away. For a simple file IO, I would even suggest using a different mechanism. Look at the MSDN for the System.IO.File Class for easier methods to read lines or write lines to a file.
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.
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;
}
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.