2

What I've done is created a base class of 'Attribute' in C#. From there I created other classes which inhert Attribute and add any additional properties as necessary. However when I try to create my observable collection which contains all these various attributes I get an underline here

private ObservableCollection<Attribute> _attributes;

under 'Attribute' saying: Using the generic type 'Attribute< TValue >' requires one type arguments. The reason for the base class of Attribute is so I can create multiple attributes as seen below.

Attribute Class

using System.Collections.Generic;

namespace ExampleTool.Model
{
    public class Attribute<TValue>
    {
        public string Key { get; set; }
        public TValue Value { get; set; }
    }

    public class FloatAttr : Attribute<float>
    {
        public string Label { get; set; }
        private float minValue { get; set; }
        private float maxValue { get; set; }
    }

    public class IntAttr : Attribute<int>
    {
        public string Label { get; set; }
        private float minValue { get; set; }
        private float maxValue { get; set; }
    }

    public class StringAttr : Attribute<string>
    {
        public string Label { get; set; }
    }

    public class BoolAttr : Attribute<bool>
    {
        public string Label { get; set; }
    }

    public class ListStringAttr : List<string>
    {
        public string Label { get; set; }
    }
}

ViewModel - where error occurs...

using System.Collections.Generic;
using System.Collections.ObjectModel;
using ExampleTool.Model;
using ExampleTool.Helper;

namespace ExampleTool.ViewModel
{
    public class AttributeViewModel : ObservableObject
    {
        private ObservableCollection<Attribute> _attributes;
        public ObservableCollection<Attribute> Attributes
        {
            get { return _attributes; }
            set
            {
                _attributes = value;
                NotifyPropertyChanged("Attributes");
            }
        }

        public AttributeViewModel()
        {
            //hard coded data for testing
            Attributes = new ObservableCollection<Attribute>();

            FloatAttr floatAttr = new FloatAttr();
            Attributes.Add(floatAttr);

            IntAttr intAttr = new IntAttr();
            Attributes.Add(intAttr);

            StringAttr stringAttr = new StringAttr();
            Attributes.Add(stringAttr);

            BoolAttr boolAttr = new BoolAttr();
            Attributes.Add(boolAttr);

            ListStringAttr listStringAttr = new ListStringAttr();
            Attributes.Add(listStringAttr);
        }
    }
}

Solution idea #1 - simply remove the property of value from the base class and define it in each sub class.

public class Attribute
    {
        public string Key { get; set; }
    }

    public class FloatAttr : Attribute
    {
        public float Value { get; set; }
        public string Label { get; set; }
        private float minValue { get; set; }
        private float maxValue { get; set; }
    }

    public class IntAttr : Attribute
    {
        public int Value { get; set; }
        public string Label { get; set; }
        private float minValue { get; set; }
        private float maxValue { get; set; }
    }

    public class StringAttr : Attribute
    {
        public string Value { get; set; }
        public string Label { get; set; }
    }

    public class BoolAttr : Attribute
    {
        public bool Value { get; set; }
        public string Label { get; set; }
    }

    public class ListStringAttr : Attribute
    {
        public List<string> Value { get; set; }
        public string Label { get; set; }
    }
JokerMartini
  • 5,674
  • 9
  • 83
  • 193

1 Answers1

2

Your base Attribute class is a generic type, then you must add type argument to it's usage. But you can't add just T:

private ObservableCollection<Attribute<T>> _attributes;

because T is not your type parameter. You should add new non-generic base class:

public class AttributeBase
{
    public string Key { get; set; }
}

public class Attribute<TValue> : AttributeBase
{
    public TValue Value { get; set; }
}

And implement AttributeRetriever like in this question:

public Attribute<T> GetAttribute<T>() where T: DatabaseItem, new()
{
    return _attributes.OfType(typeof(Attribute<T>)).FirstOrDefault as Attribute<T>;
}

Good news are that your WPF View can works fine without type parameter because Binding uses reflection. Then if you no need to have an access to your properties in code you no need to implement retriever too.

Community
  • 1
  • 1
Vadim Martynov
  • 8,602
  • 5
  • 31
  • 43
  • where does the public static function get placed? – JokerMartini Dec 16 '15 at 11:50
  • see edit above, let me know how you feel about that solution idea? – JokerMartini Dec 16 '15 at 11:54
  • @JokerMartini not static, it's my fault. It should be implemented in place where you need to retrieve specific Attribute object in your code (for example, in ViewModel). If you just add elements in collection and display them in your vieew, you no need to add this function. – Vadim Martynov Dec 16 '15 at 11:55
  • @JokerMartini in your solution I see duplicate code of Value property. But it will work fine too. – Vadim Martynov Dec 16 '15 at 11:56