CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 8 of 8
  1. #1
    Join Date
    Oct 2019
    Posts
    15

    [RESOLVED] Looking for suggestions for class design for datagridview datasource

    I have a ton of data that I want to present in a dataGridView. The columns change from time to time. So I am using a List<Class> datasource to bind to the datagridview to help manage all of this, and so far that is working well.

    But I am wondering if there is a better way to structure the class itself for ease in accessing the data it contains.

    I have numeric data that needs to be stored as numeric data but presented as formatted strings in the control. So I have set up private fields for storing the numeric data and created set{fieldname}(foo) and get{fieldname}() methods to access the data in the private fields. Then I link the public properties to formatted strings derived from the private data.

    Is that a smart way to do it? Is there a better way? I am a bit of a noob with C# and trying to learn best practices or at least better practices.

    Here is a test example of the kind of class that I might bind to the control as a list:

    Code:
    public class clsTest
    {
        // Private data that isn't part of the datasource
        private String FNameValue = String.Empty;
        private Decimal SignBonusValue = 0;
        private int SalaryTypeValue = 1;
        private Decimal SalaryValue = Convert.ToDecimal(50000);
    
        // Methods to assign values to private data
        public void setSignBonus(Decimal v)
        {
            this.SignBonusValue = v;
        }
        public void setSalaryType(int v)
        {
            this.SalaryTypeValue = v;
        }
        public void setSalary(Decimal v)
        {
            this.SalaryValue = v;
        }
    
        // Methods to return values from private data
        public Decimal getSignBonus()
        {
            return this.SignBonusValue;
        }
        public int getSalaryType()
        {
            return this.SalaryTypeValue;
        }
        public Decimal setSalary()
        {
            return this.SalaryValue;
        }
    
        // Public properties that are used by the datasource:
        public String FName => this.FNameValue;
        public String SignBonus => String.Format("${0,10:#,##0.00}", this.SignBonusValue);
        public String Salary => this.SetItemString(this.SalaryTypeValue, this.SalaryValue);
    
        public clsTest(String s)
        {
            this.FNameValue = s;
            this.SalaryValue=0;
        }
    
        private String SetItemString(int v, Decimal o)
        {
            String Item = String.Empty;
            switch (v)
            {
                case 1:
                    Item = "Base";
                    break;
                case 2:
                    Item = "Commission";
                    break;
            }
            return String.Format("{0} = {1:C2}", Item, o);
        }
    }
    Then I would call something like this to populate some data:
    Code:
        void Test_Person()
        {
            Test.AddNew("John");
            Test.AddNew("Linda");
            Test.AddNew("Rhonda");
            this.TestBindingSource.ResetBindings(true);
    
            Decimal v = Convert.ToDecimal(23.05);
            Test.TestList[1].setSignBonus(v);
            Test.TestList[1].setSalaryType(2);           
            Test.TestList[1].setSalary(Convert.ToDecimal(50000));          
        }

  2. #2
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Looking for suggestions for class design for datagridview datasource

    Rather than using private fields and accessor methods, you can just use auto-properties.

    For example, this code is replaced with:
    Code:
    private Decimal SignBonusValue = 0; private int SalaryTypeValue = 1; 
    
    private data public void setSignBonus(Decimal v)
    {
        this.SignBonusValue = v; 
    } 
    public Decimal getSignBonus() 
    { 
        return this.SignBonusValue; 
    }
    Can be replaced with an auto-property:
    Code:
    public decimal SignBonus { get; set; }

  3. #3
    Join Date
    Oct 2019
    Posts
    15

    Re: Looking for suggestions for class design for datagridview datasource

    How do I prevent those new public properties from showing up in the datagridview when I use a list of this as the bound datasource? I am binding to the list of clsTest, which as I understand it creates a bound column for every public property?

    I would surely prefer to do it this way but I did not think that I could, and still get a clean dgv binding with it. The way I am doing it now, I process the private fields into public properties that look exactly how I want them presented in the dgv.

  4. #4
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Looking for suggestions for class design for datagridview datasource

    Got it.

    Use private getters:
    Code:
    public decimal SignBonusValue { private get; set; }
    Then you can new up the object in one step with:
    Code:
    var item = new ClsTest
    {
      SignBonusValue = Convert.ToDecimal(23.05),
      SalaryTypeValue = 2,
      SalaryValue = Convert.ToDecimal(50000);
    };

  5. #5
    Join Date
    Oct 2019
    Posts
    15

    Re: Looking for suggestions for class design for datagridview datasource

    This is great - this is exactly what I was hoping to learn to be able to do.

    I am still not exactly sure how it works - but it works great. So using private getters prevents the property from being included in the binding?

    Thanks

  6. #6
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: [RESOLVED] Looking for suggestions for class design for datagridview datasource

    I assume so as far as how it binds. Auto-Properties are syntactic sugar in C#.

    When you create an auto-property, the compiler underneath the covers creates a private field and a pair of get/set methods.

    When you create
    Code:
    public decimal SignBonusValue { private get; set; }
    The compiler creates IL code that represents
    Code:
    private decimal _SignBonusValue;
    public void SignBonusValue_set(decimal value)
    {
      _SignBonusValue = value;
    }
    private decimal SignBonusValue_get()
    {
      return _SignBonusValue;
    }
    Last edited by Arjay; February 22nd, 2020 at 02:14 PM.

  7. #7
    Join Date
    Oct 2019
    Posts
    15

    Re: [RESOLVED] Looking for suggestions for class design for datagridview datasource

    Right which solves my binding problem because BindingSource will only bind to properties not fields, so when the compiler creates it as a private field that hides it from the binding source. Makes sense.

    Thanks again.

  8. #8
    Join Date
    Oct 2019
    Posts
    15

    Re: [RESOLVED] Looking for suggestions for class design for datagridview datasource

    UPDATE: I just discovered this actually does not solve my problem although at first I thought it did. But it was still pretty useful because in the process of figuring out why it doesn’t solve my problem, I finally understood what was really happening which then helped me to actually solve it.

    Like I said I am a bit of a noob to C#. I did not really understand the role of get and set and the use of private in the get and set methods.

    The reason it doesn’t solve my problem is because by using a private getter, it prevents me from doing public gets, which I need to do. I need the List<> to store data both for display in my dataGridView, and also for later programmatic use, so I need set and get to both function in a public context.

    The way I solved it is by creating another class called “Values” and storing all the needed fields there, with get set left public. Then I created an instance of Values within the main class, called “Access” and now I can update all the fields under there.

    For example, instead of:
    Code:
    Test.TestList[1].setSignBonus(v);
    Test.TestList[1].setSalaryType(2);           
    Test.TestList[1].setSalary(Convert.ToDecimal(50000));
    Now I do this:
    Code:
    Test.TestList[1].Access.SignBonusValue = v;
    Test.TestList[1].Access.SalaryTypeValue = 2;       
    Test.TestList[1].Access.SalaryValue = Convert.ToDecimal(50000);
    This lets me simply specify the list of access fields once in the subclass, and also lets me both set and get them (I am using autoproperties in the subclass). So it simplifies the code and makes it a lot easier to manage than what I was doing before.

    And the dataGridView() doesn't see any of the access fields (which is the goal) because it only binds to the properties of the main class.

    Of course I had to update all the property assignments in the main class, using the ".Access." qualifier. No big deal though. Thanks for pointing me in the right direction.
    Last edited by bigteks; March 2nd, 2020 at 06:47 PM.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured