This is a migrated thread and some comments may be shown as answers.

Value converters

7 Answers 130 Views
Chart
This is a migrated thread and some comments may be shown as answers.
SteveL
Top achievements
Rank 2
SteveL asked on 09 Sep 2009, 06:13 PM
I have a chart bound to an observable collection which holds things like temperatures. The user can set the temperature units used by the program, and I need to change the chart to correspond. I'm thinking there must be a better way than iterating over all the items in the collection and converting them. Can I use a value converter (Ivalueconverter)? I can't work out how I do this so that the value converter is called for each point on the chart.  Can I do this, or do you have any better suggestions, please?

Steve

7 Answers, 1 is accepted

Sort by
0
ManniAT
Top achievements
Rank 2
answered on 09 Sep 2009, 09:29 PM
Hi,

the answer is not RadChart specific - but maybe helpful.
How about a class extension (if it's partial that would be very easy)?
This is a thing I often use for Linq2SQL classes or WCF-Proxy classes.

Regards
Manfred
PS: if this post was helpful please use "Mark as answer"


0
SteveL
Top achievements
Rank 2
answered on 10 Sep 2009, 08:59 AM
Manfred, thank you very much for your reply, but I am afraid I don't really understand it as I am pretty much a beginner at all of this. I think extensions are for use where you can't change the class? In this case the class is mine, so I can change it - it doesn't even have to be an ObservableCollection, it only exists to drive the charts.

Your answer did prompt me to think about a possible solution. I have changed the 'getter' for my class so that it converts the returned value, using a function from another class which knows how to do the conversion. This works, but it does mean that each item in the collection has to have a reference to an instance of the converting class, so I'm not sure that this is a good solution. And I probably haven't explained it very well either. I should post some code :)

Steve
0
ManniAT
Top achievements
Rank 2
answered on 10 Sep 2009, 09:41 AM
Hi Steve,

when it's your class the thing is very easy.
Build an extra property which gives a "good for the chart" value and bind this.
I'll try to explain it with a class I use in a sample:
Snippet created with CBEnhancer
public class TheData {
    #region MeassureTime
    private DateTime m_dtMeassureTime;
    public DateTime MeassureTime {
        get { return m_dtMeassureTime; }
        set { m_dtMeassureTime = value; }
    }
    #endregion
    #region TheValue
    private int m_nTheValue;
    public int TheValue {
        get { return m_nTheValue; }
        set { m_nTheValue = value; }
    }
    #endregion
    public TheData() {
        m_dtMeassureTime = DateTime.Now;
    }
    public TheData(DateTime dtTime, int nVal) {
        m_dtMeassureTime = dtTime;
        m_nTheValue = nVal;
    }
}
Now assume that TheValue can have a range from minus 300 to plus 300.
BUT - I want my chart to display only a positive range from 0 to 600.
I guess that (of course with other numbers / calculations) is your situation
The easy idea - we add a readonly property which does the maths for us:
Snippet created with CBEnhancer
#region TheBOUNDValue
public int TheBOUNDValue {
    get { return m_nTheValue+300; }
}
#endregion

And just as a little "C# lesson":
What I meant when I was talking about "extending a class.
Assume you have used Linq2SQL - this builds classes to access the data.
And since these are partial classes you can "extend" them by writing your own part of the class.
It would look like this:
Snippet created with CBEnhancer
namespace ManniAT.DataThings {
    public partial class WebContent {
        partial void OnCreated() {
            ChangeDate = DateTime.Now;
        }
    }
}

Regards
Manfred
PS: if this post was helpful please use "Mark as answer"
0
SteveL
Top achievements
Rank 2
answered on 10 Sep 2009, 10:29 AM
Thanks for that, Manfred. What you've described is pretty much what I've done. But there is a complication in that where you have the constant '300' modifying the value, my modifier can change at runtime. The values are temperatures, and are stored in the collection in Celsius. But the user can choose to switch to Fahrenheit. I have a 'settings' class which holds the current setting, and also a method which converts a temperature as required:
public float ConvertTempToDisplay(float value) 
        { 
            float num; 
 
            if (TempUnit == tempunits.F) 
                num = (value * 1.8F) + 32; 
            else 
                // C 
                num = value; 
 
            return num; 
        } 

Then I change my data class to include an instance of the Settings class, and change the getter to use the method from it to convert the data:
public class WeatherData 
     
    { 
        public UserSettings settings { getset;} 
 
        public DateTime DT { getset; } 
 
        private float _outdoortemp; 
 
        public float OutdoorTemp 
        { 
            get { return settings.ConvertTempToDisplay(_outdoortemp); } 
            set 
            { 
                _outdoortemp = value; 
                var handler = PropertyChanged; 
                if (null != handler) 
                { 
                    handler.Invoke(thisnew PropertyChangedEventArgs("OutdoorTemp")); 
                } 
            } 
        } 
 
        public event PropertyChangedEventHandler PropertyChanged; 
    } 




This all works, but I can't help thinking there has to be a better way than including that 'settings' reference in every item.

Steve





0
Accepted
ManniAT
Top achievements
Rank 2
answered on 10 Sep 2009, 12:15 PM
Hi Steve,

a converter would mean at least as much effort as your solution.
What I would consider about is having the "Settings" as static reference in the data class.
So not every instance has a reference to the settings - instead the whole class has ONE reference and the members access it.
This (of course) works only if every instance works with the same settings.

Another (I avoid such things most of the time in WPF / SL apps) approach is a "code handled" version.
You implement TWO properties in your class "OutdoorTempFar" - "OutdoorTempCen" and than you handle the event when this part of the settings changes.
In that handler you do something like this:
Snippet created with CBEnhancer
SeriesMapping seriesMapping = new SeriesMapping();
ItemMapping FarenMapping = new ItemMapping("OutdoorTempFar"DataPointMember.YValue);
ItemMapping CelsiusMapping = new ItemMapping("OutdoorTempCen"DataPointMember.YValue);
ItemMapping curMapping =null;

private void ChangeMapping() {
    if(curMapping != null) {    //if we assigned - remove
        seriesMapping.ItemMappings.Remove(curMapping);
        if(mySettingsInstance.TempUnit == "FAR") {
            curMapping = FarenMapping;
        }
        else {
            curMapping = CelsiusMapping;
        }
        seriesMapping.ItemMappings.Add(curMapping);
    }
}

Regards
Manfred
PS: if this post was helpful please use "Mark as answer"
EDIT - I posted the wrong code - sorry
0
SteveL
Top achievements
Rank 2
answered on 10 Sep 2009, 01:29 PM
Thank you very much, Manfred. I've made the settings reference static and I'm much happier with that now. I've learned a lot from our discussion, many thanks!

Steve
0
ManniAT
Top achievements
Rank 2
answered on 10 Sep 2009, 01:32 PM
You are welcome Steve,

glad to hear I could help a bit

Manfred
Tags
Chart
Asked by
SteveL
Top achievements
Rank 2
Answers by
ManniAT
Top achievements
Rank 2
SteveL
Top achievements
Rank 2
Share this question
or