Save the CheckBox state - c#

I need to know if is possible to save the state of a CheckBox in C#? I mean if I check the CheckBox and close the program, once I restart the program the CheckBox will still stay checked. Is it possible to?

This is rather a general question. You need to serialise the state yourself somehow, but how, and where to depends on a lot of things.
Possibly take a look at a Settings file for a simple start.

For this, you will need to record the state of the CheckBox yourself. For example, you could store the value in an XML document that would contain your application's UI states. An example, in a very simplistic form, you could do the following:
// ... as the application is closing ...
// Store the state of the check box
System.IO.File.WriteAllText(#"C:\AppFile.txt", this.CheckBox1.IsChecked.ToString());
// ...
// ... as the application is being initialized ...
// Read the state of the check box
string value = System.IO.File.ReadAllText(#"C:\AppFile.txt");
this.CheckBox1.IsChecked = bool.Parse(value);
As you can see, this simply stores the value in a file and reads it back in during initialization. This is not a great way of doing it, but it demonstrates a possible process to follow.

The easiest way of doing this would be to use a config XML file. You can add this very easily through visual studio, there is no need to use registry and it can be used if the app is portable as the settings are saved with the program. A tutorial of how to set this up is here:
http://www.sorrowman.org/c-sharp-programmer/save-user-settings.html

If you are using Web application cookie enabled and storing the information in cookie then it is possible.
You can checkout http://www.daniweb.com/web-development/aspnet/threads/30505
http://asp.net-tutorials.com/state/cookies/

In C# you can use the Settings file. Information how to use it can be found here : http://msdn.microsoft.com/en-us/library/aa730869%28v=vs.80%29.aspx

If you wanted to save this to the Registry you could do something like this
RegistryKey Regkey = "HKEY_CURRENT_USER\\Software\\MyApplication";
RegKey.SetValue("Checkbox", Checkbox.Checked);
but personally I would save it to the .Config file
Here is an example of how to do it using the Config File if you so desire
private static string getConfigFilePath()
{
return Assembly.GetExecutingAssembly().Location + ".config";
}
private static XmlDocument loadConfigDocument()
{
XmlDocument docx = null;
try
{
docx = new XmlDocument();
docx.Load(getConfigFilePath());
return docx;
}
catch (System.IO.FileNotFoundException e)
{
throw new Exception("No configuration file found.", e);
}
}
private void rem_CheckedChanged(object sender, EventArgs e)
{
if (rem.Checked == true)
{
rem.CheckState = CheckState.Checked;
System.Xml.XmlDocument docx = new System.Xml.XmlDocument();
docx = loadConfigDocument();
System.Xml.XmlNode node;
node = docx.SelectSingleNode("//appsettings");
try
{
string key = "rem.checked";
string value = "true";
XmlElement elem = (XmlElement)node.SelectSingleNode(string.Format("//add[#key='{0}']", key));
if (elem != null)
{
elem.SetAttribute("value", value);
}
else
{
elem = docx.CreateElement("add");
elem.SetAttribute("key", key);
elem.SetAttribute("value", value);
node.AppendChild(elem);
}
docx.Save(getConfigFilePath());
}
catch (Exception e2)
{
MessageBox.Show(e2.Message);
}
}
}

I would use Settings like this:
Assuming a boolean setting called boxChecked has been created.
//if user checks box
Properties.Settings.Default.boxChecked = true;
Properties.Settings.Default.Save();
//...
//when the program loads
if(Properties.Settings.Default.boxChecked)
{
checkBox1.Checked = true;
}
else
{
checkBox1.Checked = false;
}

Related

How do I properly create during runtime and read the properties that are stored in the config file that saved during a previous session?

I use this code here to create a user-scoped setting during runtime:
System.Configuration.SettingsProperty userScopedProperty =
new System.Configuration.SettingsProperty("New Setting");
userScopedProperty.DefaultValue = "This setting default value";
userScopedProperty.IsReadOnly = false;
userScopedProperty.PropertyType = typeof(string);
userScopedProperty.Provider =
Properties.Settings.Default.Providers["LocalFileSettingsProvider"];
userScopedProperty.Attributes.Add(typeof(System.Configuration.UserScopedSettingAttribute),
new System.Configuration.UserScopedSettingAttribute());
Properties.Settings.Default.Properties.Add(userScopedProperty);
Properties.Settings.Default["New Setting"] = "value changed to this";
Properties.Settings.Default.Save();
Properties.Settings.Default.Reload();
Which for some reason only sometimes works and will create the settings in the userSettings section in the user.config file. While executing in the same session this works:
Properties.Settings.Default["New Setting"]
But as soon as I close the application and the start it up again, that line of code will give me a System.Configuration.SettingsPropertyNotFoundException. I have tried adding Properties.Settings.Default.Reload() right before attempting to read the setting but that doesnt seem to work either.
The goal of this portion of the project is to be able to create user settings during runtime, close the program, and when you start the program again you can view those settings. You should also be able to change them at any point. I run the program in Visual Studio in debug mode, not sure if that information is needed.
So my questions are:
How do I properly create during runtime and read the properties that are stored in the user.config file that I saved in a previous session? Is there a better way to do this?
I generally keep settings like that in an XML file in IsolatedStorage. I create a ProgramSettings class that I annotate for XML serialization (using XmlRootAttribute, XmlElementAttribute, and sometimes XmlArrayAttribute and XmlArrayItemAttribute) and then I use this class to read and write that XML settings file:
public static class PersistedSettings<T> where T : class, new()
{
public static T LoadSettings(string applicationName, ISettingsErrorReporter errorReporter)
{
var filename = GetFileName(applicationName);
try
{
using (var isoStore = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly, null, null))
{
if (!isoStore.FileExists(filename))
{
return new T();
}
//otherwise
using (var settingsStream = isoStore.OpenFile(filename, FileMode.Open, FileAccess.Read))
{
var serializer = new XmlSerializer(typeof(T));
var settings = (T)serializer.Deserialize(settingsStream);
settingsStream.Close();
return settings;
}
}
}
catch (IOException ioException)
{
errorReporter.WriteError($"IO Exception:{Environment.NewLine}{ioException.Message}");
}
catch (Exception ex)
{
errorReporter.WriteError($"Exception ({ex.GetType().Name}):{Environment.NewLine}{ex.Message}");
}
//no matter what kind of exception,
return new T();
}
public static void SaveSettings(string applicationName, T settings, ISettingsErrorReporter errorReporter)
{
try
{
using (var isoStore = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly, null, null))
{
using (var settingsStream = isoStore.CreateFile(GetFileName(applicationName)))
{
var serializer = new XmlSerializer(typeof(T));
serializer.Serialize(settingsStream, settings);
//let's be safe and use both suspenders and a belt (Flush, Close, Dispose)
settingsStream.Flush();
settingsStream.Close();
}
}
}
catch (IOException ioException)
{
errorReporter.WriteError($"I/O Exception:{Environment.NewLine}{ioException.Message}");
}
catch (Exception ex)
{
errorReporter.WriteError($"Exception ({ex.GetType().Name}):{Environment.NewLine}{ex.Message}");
}
}
private static string GetFileName(string applicationName)
{
return applicationName + ".xml";
}
}
I usually use this from simple WinForms apps. I make my Form class implement this interface:
public interface ISettingsErrorReporter
{
void WriteError(string message);
}
(usually by popping up a message box)
Then I call LoadSettings in the FormLoad event and SaveSettings in the form closing event.
It's not what you are asking, but it may satisfy your needs

Method seems to be stopping data saving to text file

I have a program where the user can add products to the system, and then search them by the product name.
Everything is working fine, except at the moment is able to enter two products with the same name. I need the program to not allow this.
I have a method assigned to the 'Add' button, which saves the product name, customer name and firmware location to a text file. Here is that method:
private void button_Click(object sender, RoutedEventArgs e)
{
bool found = false;
string searchTerm = productNameTextBox.Text.ToUpper();
if ((productNameTextBox.Text == "") || (customerNameTextBox.Text == "") || (firmwareLocationTextBox.Text == ""))
{
MessageBox.Show("Please fill in all the text boxes");
}
else if (Contains(searchTerm) == true)
{
MessageBox.Show("Product already added");
}
else
{
string inputCustomerName = customerNameTextBox.Text.ToUpper();
string inputProductName = productNameTextBox.Text.ToUpper();
string inputFirmwareLocation = firmwareLocationTextBox.Text;
try
{
Product newProduct = new Product(inputProductName, inputCustomerName, inputFirmwareLocation);
newProduct.Save("Products.txt");
File.AppendAllText("ProductNames.txt", inputProductName + Environment.NewLine);
MessageBox.Show("Product added");
emptyTheTextBoxes();
}
catch
{
MessageBox.Show("Product could not be added");
}
}
}
I have also made a method which will search a text file to see if the users product name has already been stored, and then return a Boolean. This is the method:
public bool Contains (string searchTerm)
{
string line;
bool found = false;
System.IO.StreamReader file = new System.IO.StreamReader("ProductNames.txt");
while ((line = file.ReadLine()) != null)
{
if (line.Contains(searchTerm))
{
found = true;
break;
}
}
if (found == true)
{
return true;
}
else
{
return false;
}
file.Close();
}
When I try to save the input, a message box appears saying "Product could not be added". However, if I comment out the else if statement which calls the method, it works fine.
I thought it may be because I open the file when the method is called, and maybe it wasn't closing properly. So I added the 'file.Close()' and it hasn't made a difference.
I feel like I've just made a silly mistake somewhere, but its been bugging me for hours! Definitely appreciate a fresh pair of eyes!
Thanks
Lucy
In general I would suggest that you separate out your persistence of objects from your object/data management.
You are trying to read and write to the filesystem for the same file in different parts of the program and it seems like you are having an issue with the file not being released, probably because you didn't close it correctly.
You are trying to treat the file system as if it is a database, and this is probably not the best approach. There are of course use cases where this might be needed.
Instead I would suggest the following approach.
During start up read the file. Load the products into a collection
which you keep in memory.
Allow your program to read, update, create, delete products in the
collection.
During shutdown (can also be triggered manually if you want), save
your products onto disk.
This will allow you to avoid such issues. And also be quicker.
Optionally you could also then use something like HashSet<T> for your collection. This does not allow duplicate entries (remember to override equals and hashcode in your Product object). Then when trying to add to the collection if it returns false then it was not added, which would indicate a duplicate. So this might make it easier and quicker to check for you.
I had the file.close() in the wrong place. Here is where I moved it to:
public bool Contains (string searchTerm)
{
string line;
bool found = false;
System.IO.StreamReader file = new System.IO.StreamReader("ProductNames.txt");
while ((line = file.ReadLine()) != null)
{
if (line.Contains(searchTerm))
{
found = true;
break;
}
}
file.Close();
if (found == true)
{
return true;
}
else
{
return false;
}
}

Click events from PropertyGrid (e.g. open file/folder dialog)

I am using a WinForms PropertyGrid to display various configuration settings for a program. The PropertyGrid is bound to an XML document which has been Xmlserializer.Deserialize-ed. This allows a user to type in new values, which then get serialized back into the config.xml file. In some cases, these properties are just numbers, and typing in values makes sense. However, in other cases, the values are file names or directory paths, so it makes much more sense to have these entered through an OpenFileDialog or FolderBrowserDialog.
What I'd like to have happen is that the if user clicks on a folder or filename cell in the PropertyGrid, the UI will open the appropriate dialog, get a result, and enter that result into the grid, replacing the existing value. The trouble is, PropertyGrid doesn't seem to allow access to the controls inside it, so I can't respond to an OnClicked event.
Here's how I would like the code to work (EDIT: updated code):
private void propertyGrid_config_Click(object sender, EventArgs e)
{
PropertyGrid grid = (PropertyGrid)sender;
PropertyDescriptor selectedItem = grid.SelectedGridItem.PropertyDescriptor;
if (selectedItem.Category == "Files & Folders")
{
if (selectedItem.DisplayName.Contains("directory"))
{
FolderBrowserDialog folder = new FolderBrowserDialog();
if (folder.ShowDialog() == DialogResult.OK)
{
selectedItem.SetValue(grid.SelectedObject, folder.SelectedPath);
grid.Refresh();
}
}
else if (selectedItem.DisplayName.Contains("file"))
{
OpenFileDialog file = new OpenFileDialog();
if (file.ShowDialog() == DialogResult.OK)
{
selectedItem.SetValue(grid.SelectedObject, file.FileName);
grid.Refresh();
}
}
}
}
I've set the grid's "Clicked" event to this handler, but obviously that doesn't work since that only handles the container and not what's in it. (Note this handler works fine if I base it on the "PropertyChanged" event, but that's obviously not what I'm looking for.)
Is there some way to get access to the components and create the events I want? How would you conquer this issue?
In case it's relevant, here's some of the code for the PropertyGrid:
The grid exists in a class called "Configuration" which defines all the properties like this:
[Description("Folder for storing Bonding Key logs")]
[Category("Files & Folders")]
[DisplayName("Log output directory")]
public string dirLogOutput { get; set; }
The XML file will have a corresponding entry for each Property like this:
<dirLogOutput>C:\Users\AHoffman\Desktop\TestData</dirLogOutput>
The Serializer does a good job of matching data from the XML file to the grid, and vice-versa:
public Configuration TryLoadConfiguration(Configuration thisConfig)
{
string filename = GetConfigFilename();
try
{
if (!File.Exists(filename))
{
thisConfig.setDefaults();
}
else
{
using (var stream = File.Open(filename, FileMode.Open, FileAccess.Read))
{
var serializer = new XmlSerializer(typeof(Configuration));
thisConfig = (Configuration)serializer.Deserialize(stream);
}
}
}
catch (Exception ex)
{
MessageBox.Show("Failed to load configuration file during startup: " + ex.Message);
thisConfig.setDefaults();
}
return thisConfig;
}
private void SaveConfiguration(string filename, Configuration thisConfig)
{
try
{
using (var stream = File.Open(filename, FileMode.Create, FileAccess.Write))
{
var serializer = new XmlSerializer(typeof(Configuration));
serializer.Serialize(stream, thisConfig);
}
}
catch (Exception ex)
{
MessageBox.Show("Failed to save configuration file: " + ex.Message);
}
}
I note that a question like this has been asked before here but with no answers. Hopefully I'm giving you enough info to get something back.
OK never mind. I found answers to my question here (for files) and here (for folders).
It all relies in using a custom UITypeEditor for each type.
[EditorAttribute(typeof(OpenFileNameEditor), typeof(System.Drawing.Design.UITypeEditor))]
[EditorAttribute(typeof(FolderNameEditor2), typeof(System.Drawing.Design.UITypeEditor))]
Thanks greatly to #Simon Mourier, #Stewy, and #tzup for their answers.

C# Linq for files user has read access to

How would I use Linq on list.Items = directoryInfo.GetFiles("\\server\share\folder\"); to include only the files the user has read access to?
...
So far only suggestions are using try/catches, or APIs that are obsolete in .NET 4.0? I'd prefer something to read the ACL's and see if the specific user or a group the user is a member of has been granted read access. I'm trying to do this for simplified management of granting reports to users on a website that won't be high traffic, so the logic that "who knows if you can actually read it when you try to open the file" doesn't pertain to this case. I sense that Microsoft should really make this task easier.
You run the risk of a race condition if you check for read permission prior to opening the file.
If you're attempting to read all of the files you have access to in a folder, better to just try opening each one and catch the UnauthorizedAccessException.
See:
how can you easily check if access is denied for a file in .NET?
How do you check for permissions to write to a directory or file?
just try this out .should work .haven't tested though
var fw = from f in new DirectoryInfo("C:\\Users\\User\\Downloads\\").GetFiles()
where SecurityManager.IsGranted(new FileIOPermission
(FileIOPermissionAccess.Write, f.FullName))
select f;
EDIT if it is just read only files then try this
var fe = from f in new DirectoryInfo("C:\\Users\\ashley\\Downloads\\").GetFiles()
where f.IsReadOnly==true
select f
Note: I haven't tested it, but in theory it should work
First, define a predicate to determine read access
bool CanRead(FileInfo file)
{
try {
file.GetAccessControl();
//Read and write access;
return true;
}
catch (UnauthorizedAccessException uae)
{
if (uae.Message.Contains("read-only"))
{
//read-only access
return true;
}
return false;
}
}
Then, it should be a simple case of using a where clause in a linq query
from file in directoryInfo.GetFiles("\\server\share\folder\")
where HaveAccess(f) == true
select f;
Tested and working, but will return false if the file is in use
void Main()
{
var directoryInfo = new DirectoryInfo(#"C:\");
var currentUser = WindowsIdentity.GetCurrent();
var files = directoryInfo.GetFiles(".").Where(f => CanRead(currentUser, f.FullName));
}
private bool CanRead(WindowsIdentity user, string filePath)
{
if(!File.Exists(filePath))
return false;
try
{
var fileSecurity = File.GetAccessControl(filePath, AccessControlSections.Access);
foreach(FileSystemAccessRule fsRule in fileSecurity.GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier)))
{
foreach(var usrGroup in user.Groups)
{
if(fsRule.IdentityReference.Value == usrGroup.Value)
return true;
}
}
} catch (InvalidOperationException) {
//File is in use
return false;
}
return false;
}

SAXParser equivalent in C#

I have below java code , I need to convert these in C#, Kindly help me ..
public class Configuration {
private ConfigContentHandler confHandler;
public Configuration() {
}
public boolean parseConfigFile() throws Exception {
boolean bReturn = true;
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
System.out.println("*** Start parsing");
try {
confHandler = new ConfigContentHandler(100);
// Configuration file must be located in main jar file folder
// Set the full Prosper file name
String sConfigFile = "configuration.xml";
// Get abstract (system independent) filename
File fFile = new File(sConfigFile);
if (!fFile.exists()) {
System.out.println("Could not find configuration file " + sConfigFile + ", trying input parameters.");
bReturn = false;
} else if (!fFile.canRead()) {
System.out.println("Could not read configuration file " + sConfigFile + ", trying input parameters.");
bReturn = false;
} else {
parser.parse(fFile, confHandler);
}
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Input error.");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("*** End parsing");
return bReturn;
}
Thanks
C# native XML parser XmlReader doesn't support SAX and is forward-only. You may take a look at this article presenting some specific points about it. You could simulate a SAX parser using XmlReader. If it doesn't suit your needs you could also use XDocument which is a different API for working with XML files in .NET. So to conclude there's no push XML parser built into .NET framework so you might need to use a third party library or COM Interop to MSXML to achieve this if you really need an event driven parser.
I used SAX for .NET in two projects successfully in the past.
http://saxdotnet.sourceforge.net/

Categories