eXpress App Framework Team

May 2006 - Posts

  • Using your own value types

    When we plan our work on the whiteboard, we write down work estimations in the form of hours, days or weeks of work: "1w", "2.5d", "4h". Now I have to write an application that supports this kind of estimation. So I thought it would be good to have a special value type called Effort:

        [TestFixture]
        public class EffortTests {
            [Test]
            public void TestParse() {
                Assert.AreEqual(5 * 8, new Effort("1w").Hours);
                Assert.AreEqual(4, new Effort("0.5d").Hours);
                Assert.AreEqual(5 * 8 + 1, new Effort("1w1h").Hours);
                Assert.AreEqual(0, new Effort("1.2.3h").Hours);
            }
            [Test]
            public void TestToString() {
                Assert.AreEqual("1w", new Effort(5 * 8).ToString());
                Assert.AreEqual("2d", new Effort(16).ToString());
                Assert.AreEqual("1w1h", new Effort(5 * 8 + 1).ToString()); 
            }
        }
    


    Here is the code to make these tests work:

        public struct Effort {
            private decimal hours;
    
            public Effort(string value) {
                this.hours = Parse(value);
            }
            public Effort(int hours) {
                this.hours = hours;
            }
            public decimal Hours {
                get { return hours; }
                set { hours = value; }
            }
            private static decimal workDayHours = 8.0m;
            public static decimal WorkDayHours {
                get { return workDayHours; }
                set { workDayHours = value; }
            }
            private static decimal workWeekHours = 40.0m;
            public static decimal WorkWeekHours {
                get { return workWeekHours; }
                set { workWeekHours = value; }
            }
    
            private static Regex regex = new Regex(@"((?'weeks'\d+(\.\d+)?)w)?((?'days'\d+(\.\d+)?)d)?((?'hours'\d+(\.\d+)?)h)?");
            private static decimal Parse(string value) {
                decimal result = 0;
                Match m = regex.Match(value);
                if (m.Groups["weeks"].Value != String.Empty) {
                    result += decimal.Parse(m.Groups["weeks"].Value) * WorkWeekHours; 
                }
                if (m.Groups["days"].Value != String.Empty) {
                    result += decimal.Parse(m.Groups["days"].Value) * WorkDayHours;
                }
                if (m.Groups["hours"].Value != String.Empty) {
                    result += decimal.Parse(m.Groups["hours"].Value);
                }
                return result;
            }
            public override string ToString() {
                string result = "";
                int w = (int)Math.Floor(hours / WorkWeekHours);
                if (w > 0) {
                    result += w.ToString("d") + "w";
                }
                int d = (int)Math.Floor((hours - w * WorkWeekHours) / WorkDayHours);
                if (d > 0) {
                    result += d.ToString("d") + "d";
                }
                decimal h = hours - w * WorkWeekHours - d * WorkDayHours;
                if (h > 0) {
                    result += h.ToString("n0") + "h";
                }
                return result;
            }
        }
    

    While it is normally a bad idea to make value types mutable, here we need a setter for the Hours property for XPO to be able to restore it from the database.

    To use a value type in the persistent XPO class, you have to use the Persistent attribute:

        public class Task : BaseObject {
            ...
            private Effort estimatedWork;
            [Persistent]
            public Effort EstimatedWork {
                get { return estimatedWork; }
                set {
                    estimatedWork = value;
                    OnChanged();
                }
            }
            ...
        }
    

    Now you can persist Effort type values in the database, but EAF still has no idea what kind of UI control to create for such types.
    I will create a Web property editor for the Effort type:

    ...
    using DevExpress.ExpressApp;
    using DevExpress.ExpressApp.Editors;
    using DevExpress.ExpressApp.Web.Editors;
    
    
    ...
        [PropertyEditor(typeof(Effort))]
        public class WebEffortEditor : WebStringPropertyEditor {
            public WebEffortEditor(Type objectType, DictionaryNode info) : base(objectType, info) {
            }
            protected override object GetControlValue() {
                return new Effort(Editor.Text);
            }
        }

    This editor will be discovered and used automatically by EAF as long as the module is loaded.

LIVE CHAT

Chat is one of the many ways you can contact members of the DevExpress Team.
We are available Monday-Friday between 7:30am and 4:30pm Pacific Time.

If you need additional product information, write to us at info@devexpress.com or call us at +1 (818) 844-3383

FOLLOW US

DevExpress engineers feature-complete Presentation Controls, IDE Productivity Tools, Business Application Frameworks, and Reporting Systems for Visual Studio, along with high-performance HTML JS Mobile Frameworks for developers targeting iOS, Android and Windows Phone. Whether using WPF, ASP.NET, WinForms, HTML5 or Windows 10, DevExpress tools help you build and deliver your best in the shortest time possible.

Copyright © 1998-2017 Developer Express Inc.
All trademarks or registered trademarks are property of their respective owners