Value converters

8 posts, 1 answers
  1. SteveL
    SteveL avatar
    68 posts
    Member since:
    Apr 2009

    Posted 09 Sep 2009 Link to this post

    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
  2. ManniAT
    ManniAT avatar
    877 posts
    Member since:
    Nov 2003

    Posted 09 Sep 2009 Link to this post

    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"


  3. UI for WPF is Visual Studio 2017 Ready
  4. SteveL
    SteveL avatar
    68 posts
    Member since:
    Apr 2009

    Posted 10 Sep 2009 Link to this post

    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
  5. ManniAT
    ManniAT avatar
    877 posts
    Member since:
    Nov 2003

    Posted 10 Sep 2009 Link to this post

    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"
  6. SteveL
    SteveL avatar
    68 posts
    Member since:
    Apr 2009

    Posted 10 Sep 2009 Link to this post

    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





  7. Answer
    ManniAT
    ManniAT avatar
    877 posts
    Member since:
    Nov 2003

    Posted 10 Sep 2009 Link to this post

    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
  8. SteveL
    SteveL avatar
    68 posts
    Member since:
    Apr 2009

    Posted 10 Sep 2009 Link to this post

    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
  9. ManniAT
    ManniAT avatar
    877 posts
    Member since:
    Nov 2003

    Posted 10 Sep 2009 Link to this post

    You are welcome Steve,

    glad to hear I could help a bit

    Manfred
Back to Top
UI for WPF is Visual Studio 2017 Ready