user7359083
user7359083

Reputation:

Using a list of a custom class as a persistent setting in Visual Studio for C#

I am attempting to create a project in C# where the user enters their budget information as well as their transaction (recording the amounts and category to determine whether they are under or over budget).

I have a custom transaction class:

class Transaction
{
    private int id;
    private int year;
    private int month;
    private int day;
    private string memo;
    private string category;
    private decimal amount;

    public Transaction(int tranid, int tranyear, int tranmonth, int tranday, 
        string tranmemo, string trancategory, decimal tranamount)
    {
        id = tranid;
        year = tranyear;
        month = tranmonth;
        day = tranday;
        memo = tranmemo;
        category = trancategory;
        amount = tranamount;
    }
}

Throughout the project, I decided to try using the built in persistent settings feature included with Visual Studio to create a List object of "Transaction " type, as seen below.

<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="Budget.Properties" GeneratedClassName="Settings">
  <Profiles />
  <Settings>
    <Setting Name="transactions" Type="System.Collections.Generic.List&lt;Transaction&gt;" Scope="User">
      <Value Profile="(Default)" />
    </Setting>
  </Settings>

Since the List object by default is not initialised - inside main, I use:

Properties.Settings.Default.transactions = new List<Budget.Transaction>();

Properties.Settings.Default.transactions.Add(
    new Transaction(1, 2017, 7, 27, "Birthday transaction", "Parties", 100.00m));

Properties.Settings.Default.Save();

Which initialises the object and allows me to write and read perfectly to the list item. Everything functions properly at this point. The issue occurs when it saves the persistent settings. I have isolated the issue to be when the list is of a custom class type. As the List saves easily and properly when it is of string type.

Attempting to save the settings results in a user.config file of:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
            <section name="Budget.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
        </sectionGroup>
    </configSections>
    <userSettings>
        <Budget.Properties.Settings>
            <setting name="transactions" serializeAs="Xml">
                <value />
            </setting>
        </Budget.Properties.Settings>
    </userSettings>
</configuration>

In the end, my question is... Is it possible to accomplish this? is it possible to use the built in persistent settings feature to save a List object with the type of a custom class? Or is it only viable when using the built in data types like string or int?

Upvotes: 1

Views: 433

Answers (2)

Drunken Code Monkey
Drunken Code Monkey

Reputation: 1839

The problem you have is that your transaction object is not serializable. In order to save the transaction details in the file, you have to change your class to expose public properties, not private fields. I am not sure if you need to mark the class as serializable as well, I think it should work just by having public properties.

public class Transaction
{
    public int id { get; set; }
    public int year { get; set; }
    public int month { get; set; }
    public int day { get; set; }
    public string memo { get; set; }
    public string category { get; set; }
    public decimal amount { get; set; }
}

EDIT: After checking, having public fields would be fine too:

Items That Can Be Serialized

  • The following items can be serialized using the XmLSerializer class:
  • Public read/write properties and fields of public classes.
  • Classes that implement ICollection or IEnumerable.
    • Only collections are serialized, not public properties.
  • XmlElement objects.
  • XmlNode objects.
  • DataSet objects.

However...

This is not really the best place to put transaction data. You can use the same technique (serializing to XML) and just save them into a separate file, or use the proper way to store this kind of data, a database. I highly recommend you use Linq to SQL. You can read about how to create your database and how to work with Linq to SQL here. It is essentially a lightweight Entity Framework.

Upvotes: 1

Scott Hannen
Scott Hannen

Reputation: 29207

The type you want in your Settings section is this:

System.Collections.Generic.List`1[[WindowsFormsApp1.Transaction WindowsFormsApp1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]

Except replace everything inside the brackets with the full name of your Transaction class.

There's probably a more elegant way to get the full name. I'm just lazy. I'd put a line of code in my app like

var x = typeof(List<Transaction>).FullName;

and set a breakpoint.

Upvotes: 0

Related Questions