Xamarin.Forms Droid project: How to store some data on OnHandleIntent event. I'm trying save data in Application.Current.Properties. When application active/open there is no problem, but when application closed data not saved. Any help would be appreciated. Below code example:
[Service]
public class GCMIntentService : IntentService
{
//other methods
protected async override void OnHandleIntent(Intent intent)
{
//Some code for push notification
Application.Current.Properties.Add("key", "value");
Application.Current.SavePropertiesAsync();
}
}
Xamarin.Forms Android: Save/Store some data on OnHandleIntent event
The Application.Current.Properties is just a dictionary of objects you can stick anything you want in there, including your own classes which will get serialized, and the properties collection is read from a file and this is done automatically.
However, the entire dictionary is serialized together in a file, an exception during reading or deserialization of that file will be catched and just leave you with an empty Properties collection.
Solution :
You could use SharedPreferences to Save/Store some data, as the document said :
The SharedPreferences class provides a general framework that allows you to save and retrieve persistent key-value pairs of primitive data types. You can use SharedPreferences to save any primitive data: booleans, floats, ints, longs, and strings. This data will persist across user sessions (even if your application is killed).
In Xamarin.Android, You'll need to get the instance of ISharedPreferences and use that to update/change/delete preferences. As Tom Opgenorth said, there are a couple of ways to get an instance of ISharedPreferences :
Activity.GetPreferences
would get you preferences specific to that activity. Probably not what you want.
Context.GetSharedPreferences
can get you application level preferences.
PreferenceManager.DefaultSharedPreferences
will give you an ISharedPreference instance for a given context.
The actual saving is done by an instance of ISharedPreferencesEditor, which you get get by invoking the method ISharedPreferencesEditor.Apply(). Here is an example :
Save your data :
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(this);
ISharedPreferencesEditor editor = prefs.Edit();
editor.PutString("number", "Value");
editor.Apply();
Restore your data :
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(this);
var a = prefs.GetString("number", "null");//"null" is the default value
Related
I am trying to do a "ToDoListApp" and my problem is that when I add some tasks to do and then close the app everything is deleted and the app starts anew.
I saw some other similar questions and it seems the solution is OnSaveInstanceState(Bundle outState) but I have a generic list with a class that I made List<MyClass>. My Problem is that when I write outstate.Put… there is no option for my array I can only choose between int, string, charsequence and parcelable. So my question is how can I save the state of my app?
What you are trying to do here is a thing you should be doing using an SQLite mobile database instead, Can be done like so :
Download the NuGet package sqlite-net-pcl by Frank A. Krueger
Using SQLite, Create a SQLite connection object
var db = new SQLiteConnection (dbPath);
After you have established a connection create your table something like this :
db.CreateTable<MyClass>();
Then insert the data that you want to insert into to the table something like this:
db.Insert(_yourClassObject);
Retrieve Data something like this;
var stock = db.Get<MyClass>(**yourPrimaryId**); //single object based on condition
var stockList = db.Table<MyClass>(); //The list of all data in this table.
For a better understanding of how it works refer this
Update
If you want to do it using shared preferences the way to do it would be converting it to JSON and then storing it to preferences as a string something like this:
Using Newtonsoft JSON package:
List<MyClass> your_Object;
your_Object=FooValueAssigned;// Assumed assignment
string yourString=JsonConvert.SerializeObject(your_Object); //It accepts any object in your case give your list here
Now Save it in shared preferences like this:
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences (mContext);
ISharedPreferencesEditor editor = prefs.Edit ();
editor.PutString("your_list", yourString);
// editor.Commit(); // applies changes synchronously on older APIs
editor.Apply(); // applies changes asynchronously on newer APIs
Retrieve from shared preferences something like this:
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences (mContext);
string mString = prefs.GetString ("your_list", <default value>);
Convert it back to your object type something like this:
var yourObjectFromPref= JsonConvert.DeserializeObject<List<MyClass>>(mString);
We've searched all over stack overflow and similar sites for something that will work for our app, but everything gets us only halfway there.
We have an application that allows the user to drag and drop devices onto a drop canvas. Upon the device being dropped, their "router properties" are created, and you can change their name, address, add notes.
We also let the user connect lines between the devices. (We also add the router properties that are created to an observable collection).
We have tried xmlserialization, and it let us save the physical side of the device, but upon loading the xml file, it no longer has the address, notes, etc attached to any saved device, and doesn't allow for adding connections or going to its properties.
I realize that we need to somehow serialize the code behind, then add it back in to each device upon de-serializing, but we can't seem to find a way to serialize the observable collection of router properties.
Does anyone have any suggestions on the simplest way to allow us to save the canvas, children, and their code behind properties? I am attaching pictures for reference, the router properties class and I'm happy to include any code if needed. We really appreciate any help at all.
Warm Regards,
Tyler
For example
Class
public class RouterProperties : INotifyPropertyChanged
{
private ArrayList incomingConnections = new ArrayList();
private ArrayList outgoingCnnections = new ArrayList();
private bool isLocked = true;
private bool isSelected = false;
private string deviceName = "Router";
private string hostName = "Host name";
private string routerIP = "192.168.0.1";
private string note = "Notes";
private string status = "Yellow";
private BitmapImage icon;
// getters and setters removed for brevity
public ArrayList IncomingConnections
...
public ArrayList OutgoingCnnections
...
public bool IsLocked
...
public bool IsSelected
...
public string DeviceName
...
public string HostName
...
public string RouterIP
...
public string Note
...
public string Status
...
public BitmapImage Icon
...
MainWindow Class
public ObservableCollection<RouterProperties> devices = new ObservableCollection<RouterProperties>();
EDIT Code to save xaml
// De-Serialize XML to UIElement using a given filename.
public static UIElement DeSerializeXAML(string filename)
{
// Load XAML from file. Use 'using' so objects are disposed of properly.
using (System.IO.FileStream fs = System.IO.File.Open(filename, System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
return System.Windows.Markup.XamlReader.Load(fs) as UIElement;
}
}
// Serializes any UIElement object to XAML using a given filename.
public static void SerializeToXAML(UIElement element, string filename)
{
// Use XamlWriter object to serialize element
string strXAML = System.Windows.Markup.XamlWriter.Save(element);
// Write XAML to file. Use 'using' so objects are disposed of properly.
using (System.IO.FileStream fs = System.IO.File.Create(filename))
{
using (System.IO.StreamWriter streamwriter = new System.IO.StreamWriter(fs))
{
streamwriter.Write(strXAML);
}
}
}
private void menuSave_Click(object sender, RoutedEventArgs e)
{
Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
dlg.FileName = "UIElement File"; // Default file name
dlg.DefaultExt = ".xaml"; // Default file extension
dlg.Filter = "Xaml File (.xaml)|*.xaml"; // Filter files by extension
// Show save file dialog box
Nullable<bool> result = dlg.ShowDialog();
// Process save file dialog box results
if (result == true)
{
// Save document
string filename = dlg.FileName;
SerializeToXAML(canvasMain, filename);
}
}
private void menuLoad_Click(object sender, RoutedEventArgs e)
{
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
dlg.DefaultExt = ".xaml"; // Default file extension
dlg.Filter = "Xaml File (.xaml)|*.xaml"; // Filter files by extension
// Show open file dialog box
Nullable<bool> result = dlg.ShowDialog();
// Process open file dialog box results
if (result == true)
{
string filename = dlg.FileName;
Canvas canvas = DeSerializeXAML(filename) as Canvas;
// Add all child elements (lines, rectangles etc) to canvas
while (canvas.Children.Count > 0)
{
UIElement obj = canvas.Children[0]; // Get next child
canvas.Children.Remove(obj); // Have to disconnect it from result before we can add it
canvasMain.Children.Add(obj); // Add to canvas
}
}
}
Unfortunately i dont see a solve for your current approach, or at least none that has come to mind.
Here are the fundamentals of the problem
Serialization Limitations of XamlWriter.Save
Run-Time, Not Design-Time Representation
The basic philosophy of what is serialized by a call to Save is that
the result will be a representation of the object being serialized, at
run-time. Many design-time properties of the original XAML file may
already be optimized or lost by the time that the XAML is loaded as
in-memory objects, and are not preserved when you call Save to
serialize. The serialized result is an effective representation of the
constructed logical tree of the application, but not necessarily of
the original XAML that produced it. These issues make it extremely
difficult to use the Save serialization as part of an extensive XAML
design surface.
Extension References are Dereferenced
Common references to objects made by various markup extension formats,
such as StaticResource or Binding, will be dereferenced by the
serialization process. These were already dereferenced at the time
that in-memory objects were created by the application runtime, and
the Save logic does not revisit the original XAML to restore such
references to the serialized output. This potentially freezes any
databound or resource obtained value to be the value last used by the
run-time representation, with only limited or indirect ability to
distinguish such a value from any other value set locally. Images are
also serialized as object references to images as they exist in the
project, rather than as original source references, losing whatever
filename or URI was originally referenced. Even resources declared
within the same page are seen serialized into the point where they
were referenced, rather than being preserved as a key of a resource
collection.
My first solution would have been to assign a GUID or id to each control and router property. however seemingly this wont work, XamlWriter.Save just doesn't preserve bindings or things of that nature.
However i think you need to attack this from a ViewModel first approach
That's to say, that your ViewModel needs to keep all the implementation properties of your visual objects, the locations and anything needed to rebuild your canvas visually. As you create each visual router you need to keep all of its relevant state somewhere
Even if the implementation details are separate from the the Router ViewModel you could serialize them both and have some sort of ID to relink them at runtime.
Though my Spidey senses tells me you should redesign the architecture a bit to put all the relevant in a single Higher-Level ViewModel, though this really all depends on what the architecture of the application is.
Maybe you could have a structure like this
[Serializable]
public class RouterAndState
{
public RouterProperties {get;set;}
Public RouterVisualState {get;set;}
}
[Serializable]
public class RouterVisualState
{
// its location (x,y) and anything else it needs to be recreated
}
If you are saving the router properties to a db the router entity really doesn't care what the visual layout of the canvas is, and its not something that really should be saved but maybe it can be saved in a related table that has a map to the routers used and a map to its layout, Ie RouterMap Table, with foreign keys to the RouterProperties and Visual Layout Configuration
The other way is to just generate the visual state from the routerProperties and auto generate the layout, this is neat but you will need implement a lot more logic to auto configure how its laid-out when loading .
However if this is a fairly simple things, just serialize it all to a file using something like the above and be done with it
I hope this helps
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.
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.
I am building an application, which has a form where the user can configure all his settings. When the application is loaded, the previously configured settings should reflect to the GUI (The UI should be consistent to the saved settings).
What I am currently doing is creating the settings on the project properties and I have a LoadSettings() method, which gets the values and outputs them to each component on the UI.
The thing is that this is getting VERY messy, and I don't like it at all.
So, that got me wondering, what are the correct approaches to achieve what I want, but yet getting high quality code? Any patterns for that?
private void LoadConfigs()
{
checkBoxStartOnStartup.Checked = ExistKeyValue(#"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", "Wallbase Downloader");
checkBoxCheckWallbaseOnline.Checked = Settings.Default.CheckWallbaseOnlineStartup;
comboBoxResolution.SelectedIndex = comboBoxResolution.FindStringExact(Settings.Default.Resolution == string.Empty
? GetScreenResolution()
: Settings.Default.Resolution);
comboBoxCondition.SelectedIndex = Settings.Default.ConditionIndex;
textBoxWallpaperFolders.Text = Settings.Default.WallpaperFolder;
numericChangeInterval.Text = Convert.ToString(Settings.Default.ChangeIntervalValue);
comboBoxChangeInterval.SelectedIndex = Settings.Default.ChangeIntervalIndex;
numericCheckInterval.Text = Convert.ToString(Settings.Default.CheckIntervalValue);
comboBoxCheckInterval.SelectedIndex = Settings.Default.CheckIntervalIndex;
numericWallpapersToLookFor.Text = Settings.Default.WallpapersToLookFor.ToString();
}
Well, WinForms are not the cleanest framework around...
What you could do is to load all settings when your application starts up and store them in some storage that is available to all forms, e.g. in a static property in a helper settings class.
You can then access that static property from each form when it loads and make all necessary changes to the form based on the settings.
You can use a Hashtable and use English strings for key to make your code really readable. Then serialize it to file on exit and deserialize it back when application loads. Save the serialized file to some common location so that you do not lose it.