How to implement states on a windows form appliaction - c#

I am developing a c# windows form application. In my application i have 3 forms (main form that has a list box and two buttons (Check in and check out), check in form and the check out form). On the main form, the list box contain user names, if a user select their name for the first time, the check in button must be enabled for the user to check in... But if the user checks in and then closes the application, when they reopen it, the button check out should be enabled and check in disabled.
I have been told to use the application/user states, but since I'm new in programming, i don't know how to implement the windows form states.
What should i do?
Thank you

There is no such thing as "Windows Forms states". You have several options to implement somthing like this, among which are:
Use a database (this makes sense if you have a varying number of users and a database server available)
Use user settings (this is a builtin mechanism of the .NET framework, but may not be suitable for lots of users)
Use a simple XML file to store the states of all users.
All three solutions require you to sort of "get into things". Write more about what you have available (database server, etc.) or whether you want a fixed number of users and I can extend this answer to help you get started.
I'm going to line out how to do number 2:
Create a little helper class that assigns a state to a user name:
public class UserState
{
public string UserName { get; set; }
public bool CheckedIn { get; set; }
public override string ToString() { return String.Format("{0}={1}", UserName, CheckedIn); }
}
This class allows you to store a user name and the checked in state and by calling ToString() get a value in the form "user=false".
Then, create a user scoped application setting (go to settings-tab of project settings and add a new setting of type System.Collections.Specialized.StringCollection) named UserStates. You can access this setting from code as Properties.Settings.Default.UserStates. It is basically a list of strings.
To add and persist a new entry you could do this:
UserState state = new UserState() { UserName = "Test", CheckedIn = false };
Properties.Settings.Default.UserStates.Add(state.ToString());
Properties.Settings.Default.Save();
The state for user "Test" (and the previously existing entries) are now stored across program restarts.
Now the idea is to build a list of users and their states when starting the program and to store this list when exiting.
Declare this as a member variable in the class:
private List<UserState> userStates = new List<UserState>();
Do the following in the form's OnLoad event:
if (Properties.Settings.Default.UserStates == null || Properties.Settings.Default.UserStates.Count == 0)
{
// Add your users to the collection initially. This is the first
// run of the application
userStates.Add(new UserState() { ... });
...
}
else
{
// Each line in the setting represents one user in the form name=state.
// We split each line into the parts and add them to the internal list.
for (int i = 0; i < Properties.Settings.Default.UserStates.Count; i++)
{
string stateLine = Properties.Settings.Default.UserStates[i];
string[] parts = stateLine.Split('=');
userStates.Add(new UserState() { UserName = parts[0].Trim(), CheckedIn = Boolean.Parse(parts[1].Trim()) });
}
}
This creates a new entry in an internal list of users for each stored line in the collection setting.
When a button is clicked, change the state in the respective UserState object in the list.
Do the following in the form's OnClose event:
// Create the collection from scratch
Properties.Settings.Default.UserStates = new System.Collections.Specialized.StringCollection();
// Add all the users and states from our internal list
foreach (UserState state in userStates)
{
Properties.Settings.Default.UserStates.Add(state.ToString());
}
// Save the settings for next start
Properties.Settings.Default.Save();
This persists the current list of user states to the setting.
Please note: I have tested this in Visual Studio now and it works. I leave the question of how to map the list box entries to the UserState objects in the internal list to you/as topic for a new question :-D
The downside of this approach: It is not very flexible - adding more states per user involves some coding.
It could be better for you to read about typed datasets and how to store/read them from XML. This gives you some sort of "database feeling" without actually having to use a database.

Related

How do I reference text boxes from multiple windows in a WPF application?

I'm creating a note taking application with multiple windows to gather information. How do I save the values of multiple text boxes in multiple windows to variables on button click?
I have successfully implemented it in the MainWindow and I'm having trouble extending the paradigm across multiple windows. I have a feeling it's associated with not assigning a name to the instance of the second window, but I'm not sure how it works.
This is the code for the function that works in the MainWindow:
public static void CopyText()
{
string srText = ((MainWindow)Application.Current.MainWindow).srBox.Text;
string contactText = ((MainWindow)Application.Current.MainWindow).contactBox.Text;
string usernameText = ((MainWindow)Application.Current.MainWindow).usernameBox.Text;
string generalText = ((MainWindow)Application.Current.MainWindow).generalBox.Text;
string copyText = "";
Clipboard.SetDataObject(copyText);
}
This is the code for the function in the CreditWindow that does not work:
public static void CopyCreditText()
{
string srText = ((MainWindow)Application.Current.MainWindow).srBox.Text;
string usernameText = ((MainWindow)Application.Current.MainWindow).usernameBox.Text;
string buyerText = ((CreditWindow)Application.Current.MainWindow).buyerBox.Text;
string itemText = ((CreditWindow)Application.Current.MainWindow).itemBox.Text;
string amountText = ((CreditWindow)Application.Current.MainWindow).amountBox.Text;
string typeText = ((CreditWindow)Application.Current.MainWindow).typeBox.Text;
string reasonText = ((CreditWindow)Application.Current.MainWindow).reasonBox.Text;
string copyText = "";
Clipboard.SetDataObject(copyText);
}
When I run this code, I get an error from Visual Studio on this line:
string buyerText = ((CreditWindow)Application.Current.MainWindow).buyerBox.Text;
that states "Unable to cast object of type 'MSONotes.MainWindow' to type 'MSONotes.CreditWindow'.
The error is because Application.Current.MainWindow is just that, the main window of the entire application. It doesn't change no matter how many child windows exist. It won't become a CreditWindow.
Unless the windows have references to each other, you should handle this kind of data passing well behind the view layer. I lied, you should do that regardless, but references would allow you to keep cheating. In a properly architected application:
Those text boxes would be bound to fields in a view model
The button click would push the values to some model (shared by the other window's VMs, ideally using dependency injection)
Via an event or similar the service would notify all VMs that new data was available
They would update their own appropriate fields
The other windows view's would update automatically due to the VM update.
Basically, you are going to need to do WPF properly (with MVVM) and not hack it together like that.

UWP Create Tile Menu Links

I want to have for my UWP App on the Tile Menu some Deeplinks to specific things in my App.
Basicly i want to make the same like the XBOX App
Xbox tile menu
How do i create those links?
That's called the jump list, learn more here: https://learn.microsoft.com/en-us/uwp/api/windows.ui.startscreen.jumplist
You can use the Windows.UI.StartScreen.JumpList type to access the feautres of the app's jumplist. These actions then appear both in Start menu and in Task bar.
Using the SystemGroupKind property you can specify what should be displayed in the system area of the jump list - either Recent for recently opened files, Frequent for frequently opened items or None for nothing. To make this area alive, you need to use file type association for your app.
Then for your own custom items you utilize the Items property, where you can simply add new links -
// Create JumpListItem - first parameter is the activation argument,
// second the title of the task
var taskItem = JumpListItem.CreateWithArguments( "/Argument", "Write message");
// Set the description (optional)
taskItem.Description = "Write a message to someone.";
// Set the icon, URI must be ms-appx: or ms-appdata:
taskItem.Logo = new Uri("ms-appx:///Assets/WriteMessage.png");
// You may also specify a GroupName to group the tasks
return taskItem;
When the user clicks a task, you can check for the arguments in App.xaml.cs OnLaunched method:
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
if (e.Kind == ActivationKind.Launch && e.Arguments == "/Argument")
{
// Navigate to specific method
}
}

What is the best way to store some data in VSTO addin?

I have developed one outlook add-in, that has to be On or Off.
to do that i have declared one static variable as shown below,
ThisAddIn.cs
public static bool isAddInOn = false;
RibbonButton.cs
private void btnRibbon_Click(object sender, RibbonControlEventArgs e)
{
if (ThisAddIn.isAddInOn )
{
ThisAddIn.isAddInOn = false;
btnRibbon.Label = "Disabled";
}
else
{
ThisAddIn.isAddInOn = true;
btnRibbon.Label = "Enabled";
}
}
It is working. But the static variable reset again when i close outlook and open it again. That means when i open outlook by default my add-in is in disabled state.
I just want to store that value at some place. so i can check that value when outlook reopened.
Scenario:
1) open outlook
2) Enable add-in by clicking on its logo (that is in ribbon)
3) now close the outlook
4) when i open outlook again it must enabled
so how can i achieve this ?
There are several techniques you can use to achieve this result. For sure your settings must be serialized to some storage/deserialized during startup of add-in.
One of possible solution could be to use registry for that (in this case probably HKCU (Current user, then it will be private for each user using your add-in) and no special permission is needed.
For storing variable:
public void StoreInRegistry(string keyName, string value)
{
RegistryKey rootKey = Registry.CurrentUser;
string registryPath = #"Software\YourCompanyName\YourAddInName";
using (RegistryKey rk = rootKey.CreateSubKey(registryPath))
{
rk.SetValue(keyName, value, RegistryValueKind.String);
}
}
For reading variable:
public string ReadFromRegistry(string keyName, string defaultValue)
{
RegistryKey rootKey = Registry.CurrentUser;
string registryPath = #"Software\YourCompanyName\YourAddInName";
using (RegistryKey rk = rootKey.OpenSubKey(registryPath, false))
{
if (rk == null)
{
return defaultValue;
}
var res = rk.GetValue(keyName, defaultValue);
if (res == null)
{
return defaultValue;
}
return res.ToString();
}
}
Such stored/retrieved variable should be used during add-in initialization to set your properties. So modification could look like:
ThisAddin.cs
public static bool isAddInOn = ReadFromRegistry("MySetting1", "0") == "1";
RibbonButton.cs
private void btnRibbon_Click(object sender, RibbonControlEventArgs e)
{
if (ThisAddIn.isAddInOn )
{
ThisAddIn.isAddInOn = false;
btnRibbon.Label = "Disabled";
}
else
{
ThisAddIn.isAddInOn = true;
btnRibbon.Label = "Enabled";
}
StoreInRegistry("MySetting1", ThisAddIn.isAddInOn ? "1" : "0");
}
Other options could serialization to file - some class with settings serialized to i.e. isolated storage, database (local or central) etc.
I've used several methods over the years to store configuration data for users.
Properties.Settings.Default.Properties, so writing in the application project properties. It's solid, never had an issue with it, for hundreds of users over several years.
Local config files in text, so writing to a known area for the user with fallback. In a stable environment, one can choose the home area for the user, and read/write to the local config file, which also makes it accessible to support if it breaks and needs manual changes. As a fallback, one could write to the local temp folder.
Registry is an option i have not used in this case, but it is likely to be a good choice.
Performance is likely a key concern considering it will impact the UI for users. Another concern is ease of use for the developer. For both, my choice would be setting it in the application's properties, where reading and writing is very simple and handled within code, and likely very fast.
Write
Properties.Settings.Default.PropertyName = propertValue;
Read
var propertValue = Properties.Settings.Default.PropertyName;
2018 UPDATED ANSWER
The recommended way to achieve this is now to use the already configured settings files in your project's properties. These files are auto-generated when create your project :
And open the following window when clicked :
You can access your settings value programmatically into Properties.Settings.Default.Properties anywhere.
The header bar at the top of the Settings page contains several controls:
Synchronize
Synchronize restores user-scoped settings that the application uses at run time or during debugging to their default values as defined at design time. To restore the data, remove run-time generated application-specific files from disk, not from project data.
Load Web Settings
Load Web Settings displays a Login dialog box that enables you to load settings for an authenticated user or for anonymous users. This button is enabled only when you've enabled client application services on the Services page and specified a Web settings service location.
View Code
For C# projects, the View Code button enables you to view the code in the Settings.cs file. This file defines the Settings class, which enables you to handle specific events on the Settings object. In languages other than Visual Basic, you must explicitly call the Save method of this wrapper class in order to persist the user settings. You usually do this in the Closing event handler of the main form. Following is an example of a call to the Save method:
C#
Properties.Settings.Default.Save();
For Visual Basic projects, the View Code button enables you to view the code in the Settings.vb file. This file defines the MySettings class, which enables you to handle specific events on the My.Settings object. For more information about accessing application settings by using the My.Settings object, see Access application settings.
For more information about accessing application settings, see Application settings for Windows Forms.
Access modifier
The Access modifier button specifies the access level of the Properties.Settings (in C#) or My.Settings (in Visual Basic) helper classes that Visual Studio generates in Settings.Designer.cs or Settings.Designer.vb.
For Visual C# projects, the access modifier can be Internal or Public.
For Visual Basic projects, the access modifier can be Friend or Public.
By default, the setting is Internal in C# and Friend in Visual Basic. When Visual Studio generates helper classes as Internal or Friend, executable (.exe) applications cannot access the resources and settings that you have added to class libraries (.dll files). If you have to share resources and settings from a class library, set the access modifier to Public.
For more information about the settings helper classes, see Manage application settings.
Settings grid
Settings Grid is used to configure application settings. This grid includes the following columns:
Name
Enter the name of the application setting in this field.
Type
Use the drop-down list to select a type for the setting. The most frequently used types appear in the drop-down list, for example, String, (Connection string), and System.Drawing.Font. You can choose another type by selecting Browse at the end of the list, and then selecting a type from the Select a Type dialog box. After you choose a type, it's added to the common types in the drop-down list (for the current solution only).
Scope
Select either Application or User.
Application-scoped settings, such as connection strings, are associated with the application. Users can't change application-scoped settings at run time.
User-scoped settings, such as system fonts, are intended to be used for user preferences. Users can change them at run time.
Value
The data or value associated with the application setting. For example, if the setting is a font, its value could be Verdana, 9.75pt, style=Bold.
Documentation link
Reading settings
Writing settings
Settings can be stored as a hidden (associated) item in a folder, such as the Inbox or the Calendar folder. For example, Outlook stores the list of categories as a hidden item in the Calendar folder. POP3 message ids are stored in a hidden item in the Inbox. The advantage of the hidden items is the roaming capability - Exchange mailbox user can see the data from any computer.
You can see the hidden items in OutlookSpy (I am its author) - click IMAPIFolder button, go to the "Associated Contents" tab.
Programmatically, such items can be accessed using MAPIFolder.GetStorage in the Outlook Object Model.

how to load a form only at the first time after program is installed

My speech recognition project include 2 forms form1 & form2. Form2 is my main form but before loading form2 my program take a variable value from user through form1 and pass it to form2. It means at start my program opens form1 takes value & pass it to form2 then form2 is shown.
Now my question is how to
make form1 load only at programs 1st launch after installation and after 1st launch directly form2 is loaded thereafter?
means form1 should not be loaded after that..
I suggest to use a simple textfile where you could store the input value recorded the first time your app starts, then, check if the file with the value exists and read it back.
For Example
string customValue = string.Empty;
string appData = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
appData = Path.Combine(appData, "MyAppName");
if(!Directory.Exists(appData))
Directory.CreateDirectory(appData);
string appDataFile = Path.Combine(appData, "MyAppNameSettings.txt");
if(File.Exists(appDataFile))
customValue = File.ReadAllText(appDataFile);
else
{
customValue = AskUserForTheFirstTimeValue();
File.WriteAllText(appDataFile, customValue);
}
The file is stored in a subfolder of the common application data (C:\programdata) created to store your data files. You check if the file exists at first launch. If the file exists you read its content (assumed to be a simple string here), if the file doesn't exist then you ask the input and store the value for the successive runs of your app.
You can create a Registry Key in Windows Registry (regedit), and when you start your program verify if its exists and the value.
Link about Registry Keys:
http://msdn.microsoft.com/en-us/library/microsoft.win32.registrykey(v=vs.110).aspx
You should have a settings file that keeps a variable like IsFirstRun = true; This application should be distributed and compiled with this file, at start up you should read this file and if you encounter the true state you should load the appropriate forms. You should also ensure that the value is immediately set to false for the second launch condition.
have a look at .net's setting class.
There are two ways I can suggest:
First one
Use the application configuration file:
Creating such file in c# is pretty easy, per usual if you start with a standard Windows Forms Project Template you will most likely already have an app.config in that project, if not, follow instructions from here (under Application Configuration Files).
Add a simple boolean value to the file like so (that appSettings-node is created under the root configuration-node:
<appSettings>
<add key="FirstRun" value="true" />
</appSettings>
In your first form, where you do your application configuration you add code to manipulate your app.config programmatically using the ConfigurationManager-Class for the event that configuration has been finished and can be saved (probably some button click, note that you will need a Reference to System.Configuration):
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
bool myVal = bool.Parse(config.AppSettings.Settings["FirstRun"].Value);
if (myVal)
{
// MessageBox.Show("yep, its true");
config.AppSettings.Settings["FirstRun"].Value = false.ToString();
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");
}
else
{
// MessageBox.Show("na, its not true anymore.");
}
Second one
Use a property grid for your application configuration:
Since from your description it seems you only use the first form to enter some application configuration values, I would recommend using the PropertyGrid-Control for that.
That control can be easily bound to an object that exposes some properties (what a surprise) that are then used to render a standardized control containing captions and value selection controls dependend on the property's types, for example:
public class Settings
{
public int MyProperty1 { get; set; }
public string MyProperty2 { get; set; }
}
Then you check at your program start, whether the configuration file (you define the path) exists, and if so, try to deserialize an object from its xml (sample below works for primitive types, for more complex ones you might have to extend the serializer, but you get the idea).
That serialized object represents your saved application settings, so you do not need to open up the propertygrid-form anymore.
If no file could be found the grid gets initialized with a simple new constructed object and you show that form:
this goes into your initialization code:
FileInfo file = new FileInfo("SaveHere.xml");
if (file.Exists)
{
using(StreamReader reader = new StreamReader("SaveHere.xml"))
{
XmlSerializer serializer = new XmlSerializer(typeof(Settings));
Settings mySettings = (Settings)serializer.Deserialize(reader);
reader.Close();
}
}
else
{
this.propertyGrid1.SelectedObject = new Settings();
// show form code
}
this code goes into the event code where you want to save your configuration
using(StreamWriter writer = new StreamWriter("SaveHere.xml",false))
{
XmlSerializer serializer = new XmlSerializer(this.propertyGrid1.SelectedObject.GetType());
serializer.Serialize(writer, this.propertyGrid1.SelectedObject);
writer.Close();
}

Reading default application settings in C#

I have a number of application settings (in user scope) for my custom grid control. Most of them are color settings. I have a form where the user can customize these colors and I want to add a button for reverting to default color settings. How can I read the default settings?
For example:
I have a user setting named CellBackgroundColor in Properties.Settings.
At design time I set the value of CellBackgroundColor to Color.White using the IDE.
User sets CellBackgroundColor to Color.Black in my program.
I save the settings with Properties.Settings.Default.Save().
User clicks on the Restore Default Colors button.
Now, Properties.Settings.Default.CellBackgroundColor returns Color.Black. How do I go back to Color.White?
#ozgur,
Settings.Default.Properties["property"].DefaultValue // initial value from config file
Example:
string foo = Settings.Default.Foo; // Foo = "Foo" by default
Settings.Default.Foo = "Boo";
Settings.Default.Save();
string modifiedValue = Settings.Default.Foo; // modifiedValue = "Boo"
string originalValue = Settings.Default.Properties["Foo"].DefaultValue as string; // originalValue = "Foo"
Reading "Windows 2.0 Forms Programming", I stumbled upon these 2 useful methods that may be of help in this context:
ApplicationSettingsBase.Reload
ApplicationSettingsBase.Reset
From MSDN:
Reload contrasts with Reset in that
the former will load the last set of
saved application settings values,
whereas the latter will load the saved
default values.
So the usage would be:
Properties.Settings.Default.Reset()
Properties.Settings.Default.Reload()
Im not really sure this is necessary, there must be a neater way, otherwise hope someone finds this useful;
public static class SettingsPropertyCollectionExtensions
{
public static T GetDefault<T>(this SettingsPropertyCollection me, string property)
{
string val_string = (string)Settings.Default.Properties[property].DefaultValue;
return (T)Convert.ChangeType(val_string, typeof(T));
}
}
usage;
var setting = Settings.Default.Properties.GetDefault<double>("MySetting");
Properties.Settings.Default.Reset() will reset all settings to their original value.
I've got round this problem by having 2 sets of settings. I use the one that Visual Studio adds by default for the current settings, i.e. Properties.Settings.Default. But I also add another settings file to my project "Project -> Add New Item -> General -> Settings File" and store the actual default values in there, i.e. Properties.DefaultSettings.Default.
I then make sure that I never write to the Properties.DefaultSettings.Default settings, just read from it. Changing everything back to the default values is then just a case of setting the current values back to the default values.
How do I go back to Color.White?
Two ways you can do:
Save a copy of the settings before the user changes it.
Cache the user modified settings and save it to Properties.Settings before the application closes.
I found that calling ApplicationSettingsBase.Reset would have the effect of resetting the settings to their default values, but also saving them at the same time.
The behaviour I wanted was to reset them to default values but not to save them (so that if the user did not like the defaults, until they were saved they could revert them back).
I wrote an extension method that was suitable for my purposes:
using System;
using System.Configuration;
namespace YourApplication.Extensions
{
public static class ExtensionsApplicationSettingsBase
{
public static void LoadDefaults(this ApplicationSettingsBase that)
{
foreach (SettingsProperty settingsProperty in that.Properties)
{
that[settingsProperty.Name] =
Convert.ChangeType(settingsProperty.DefaultValue,
settingsProperty.PropertyType);
}
}
}
}

Categories

Resources