views:

1117

answers:

5

Hi, I'm creating a simple windows Forms application using C# express 2008. I'm an experienced C++ developer, but I am pretty much brand new to C# and .NET.

I'm currently storing some of my simple application settings using the settings designer and code like this:

// Store setting  
Properties.Settings.Default.TargetLocation = txtLocation.Text;  
...  
// Restore setting  
txtLocation.Text = Properties.Settings.Default.TargetLocation;

Now I'd like to store either an array of ints ( int[] ), or possibly a List of ints ( List< int > ), as a setting. However, I can't figure out how to do this. I've searched the documentation, stackoverflow, and google, and I cannot find a decent explanation of how to do this.

My hunch based on the sparse examples I've found is that I have to create a class that is serializable that wraps my array or List, and then I will be able to use that Type in the settings designer. However, I'm not sure exactly how to do this.

Thanks in advance for your help!

A: 

I'd probably create my own custom config section / section group

McKay
Ok, that sounds promising. Can you give me more detail on that?
sidewinderguy
This might help: http://haacked.com/archive/2007/03/12/custom-configuration-sections-in-3-easy-steps.aspx
Mike Gleason jr Couturier
+8  A: 

to store:

string value = String.Join(",", intArray.Select(i => i.ToString()).ToArray());

to re-create:

int[] arr = value.Split(',').Select(s => Int32.Parse(s)).ToArray();

Edit: Abel suggestion!

Mike Gleason jr Couturier
Beat me to it, Mike.
ChrisV
and me ;-). Tip" you can remove `ToCharArray()`, and use `value.Split(',')`, which is a tad more readable.
Abel
Ok, so this looks like you are serializing the data manually into a string, and vice-versa. I guess this would work, I could just store the data as a string setting. I thought of doing something like this, but I was looking for something more "clean" or "standard" or just more .NET'ish. I'll keep this in mind though, if nothing better crops up. Thanks.
sidewinderguy
Hi, I would go with McKay's avenue then! (config section / section group)
Mike Gleason jr Couturier
I'm going to go with this because it is simple. Thanks for all the ideas everyone, I'm sure they will help down the road.
sidewinderguy
Note: You'll need to have `System.Linq` added to your usings/imports for the above trick to work.
Yadyn
A: 

I think you are right about serializing your settings. See my answer to this question for a sample:

Techniques for sharing a config between two apps?

You would have a property which is an array, like this:

/// <summary>
/// Gets or sets the height.
/// </summary>
/// <value>The height.</value>
[XmlAttribute]
public int [] Numbers { get; set; }
Philip Wallace
+1  A: 

Specify the setting as a System.Collections.ArrayList and then:

Settings.Default.IntArray = new ArrayList(new int[] { 1, 2 });

int[] array = (int[])Settings.Default.IntArray.ToArray(typeof(int));
João Angelo
+5  A: 

There is one other way to achieve this result that is a lot cleaner in usage but requires more code. My implementing a custom type and type converter the following code is possible:

List<int> array = Settings.Default.Testing;
array.Add(new Random().Next(10000));
Settings.Default.Testing = array;
Settings.Default.Save();

To achieve this you need a type with a type converter that allows conversion to and from strings. You do this by decorating the type with the TypeConverterAttribute:

[TypeConverter(typeof(MyNumberArrayConverter))]
public class MyNumberArray ...

Then implementing this type converter as a derivation of TypeConverter:

class MyNumberArrayConverter : TypeConverter
{
    public override bool CanConvertTo(ITypeDescriptorContext ctx, Type type)
    { return (type == typeof(string)); }

    public override bool CanConvertFrom(ITypeDescriptorContext ctx, Type type)
    { return (type == typeof(string)); }

    public override object ConvertTo(ITypeDescriptorContext ctx, CultureInfo ci, object value, Type type)
    {
        MyNumberArray arr = value as MyNumberArray;
        StringBuilder sb = new StringBuilder();
        foreach (int i in arr)
            sb.Append(i).Append(',');
        return sb.ToString(0, Math.Max(0, sb.Length - 1));
    }

    public override object ConvertFrom(ITypeDescriptorContext ctx, CultureInfo ci, object data)
    {
        List<int> arr = new List<int>();
        if (data != null)
        {
            foreach (string txt in data.ToString().Split(','))
                arr.Add(int.Parse(txt));
        }
        return new MyNumberArray(arr);
    }
}

By providing some convenience methods on the MyNumberArray class we can then safely assign to and from List, the complete class would look something like:

[TypeConverter(typeof(MyNumberArrayConverter))]
public class MyNumberArray : IEnumerable<int>
{
    List<int> _values;

    public MyNumberArray() { _values = new List<int>(); }
    public MyNumberArray(IEnumerable<int> values) { _values = new List<int>(values); }

    public static implicit operator List<int>(MyNumberArray arr)
    { return new List<int>(arr._values); }
    public static implicit operator MyNumberArray(List<int> values)
    { return new MyNumberArray(values); }

    public IEnumerator<int> GetEnumerator()
    { return _values.GetEnumerator(); }
    IEnumerator IEnumerable.GetEnumerator()
    { return ((IEnumerable)_values).GetEnumerator(); }
}

Lastly, to use this in the settings you add the above classes to an assembly and compile. In your Settings.settings editor you simply click the "Browse" option and select the MyNumberArray class and off you go.

Again this is a lot more code; however, it can be applied to much more complicated types of data than a simple array.

csharptest.net
Thanks this looks interesting. I'll try it out when I get the chance.
sidewinderguy