1

So I have need to dynamically add data to a class that will populated a datagridview. Below is the test code. I created a form with a datagridview and manually added the columns in the order I wanted with the datapropertynames that correspond to each property in the dataset. but the datagridview reorders them and I cant figure out why. I set the datagridview to have the order of data2,data1,CustomerName but customername keeps moving between data2 and data1. I know this may look weird with what Im trying to do but this was just a test of the concept. The implementation is that I have columns that are calculated based off data in the other columns but those columns arent sortable because they are not bound to the data. So I need this to work or a way to bind the data in the calculated columns so that its sortable. Thanks

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    public static Type BuildDynamicTypeWithProperties()
    {
        AppDomain myDomain = Thread.GetDomain();
        AssemblyName myAsmName = new AssemblyName();
        myAsmName.Name = "MyDynamicAssembly";

        // To generate a persistable assembly, specify AssemblyBuilderAccess.RunAndSave.
        AssemblyBuilder myAsmBuilder = myDomain.DefineDynamicAssembly(myAsmName,
                                                        AssemblyBuilderAccess.RunAndSave);
        // Generate a persistable single-module assembly.
        ModuleBuilder myModBuilder =
            myAsmBuilder.DefineDynamicModule(myAsmName.Name, myAsmName.Name + ".dll");



        TypeBuilder myTypeBuilder = myModBuilder.DefineType("CustomerData",
                                                        TypeAttributes.Public);
        myTypeBuilder.SetParent(typeof(TestData));

        FieldBuilder customerNameBldr = myTypeBuilder.DefineField("customerName",
                                                        typeof(string),
                                                        FieldAttributes.Private);

        // The last argument of DefineProperty is null, because the
        // property has no parameters. (If you don't specify null, you must
        // specify an array of Type objects. For a parameterless property,
        // use an array with no elements: new Type[] {})
        PropertyBuilder custNamePropBldr = myTypeBuilder.DefineProperty("CustomerName",
                                                         System.Reflection.PropertyAttributes.HasDefault,
                                                         typeof(string),
                                                         null);

        // The property set and property get methods require a special
        // set of attributes.
        MethodAttributes getSetAttr =
            MethodAttributes.Public | MethodAttributes.SpecialName |
                MethodAttributes.HideBySig;

        // Define the "get" accessor method for CustomerName.
        MethodBuilder custNameGetPropMthdBldr =
            myTypeBuilder.DefineMethod("get_CustomerName",
                                       getSetAttr,
                                       typeof(string),
                                       Type.EmptyTypes);

        ILGenerator custNameGetIL = custNameGetPropMthdBldr.GetILGenerator();

        custNameGetIL.Emit(OpCodes.Ldarg_0);
        custNameGetIL.Emit(OpCodes.Ldfld, customerNameBldr);
        custNameGetIL.Emit(OpCodes.Ret);

        // Define the "set" accessor method for CustomerName.
        MethodBuilder custNameSetPropMthdBldr =
            myTypeBuilder.DefineMethod("set_CustomerName",
                                       getSetAttr,
                                       null,
                                       new Type[] { typeof(string) });

        ILGenerator custNameSetIL = custNameSetPropMthdBldr.GetILGenerator();

        custNameSetIL.Emit(OpCodes.Ldarg_0);
        custNameSetIL.Emit(OpCodes.Ldarg_1);
        custNameSetIL.Emit(OpCodes.Stfld, customerNameBldr);
        custNameSetIL.Emit(OpCodes.Ret);

        // Last, we must map the two methods created above to our PropertyBuilder to 
        // their corresponding behaviors, "get" and "set" respectively. 
        custNamePropBldr.SetGetMethod(custNameGetPropMthdBldr);
        custNamePropBldr.SetSetMethod(custNameSetPropMthdBldr);


        Type retval = myTypeBuilder.CreateType();

        // Save the assembly so it can be examined with Ildasm.exe,
        // or referenced by a test program.
        myAsmBuilder.Save(myAsmName.Name + ".dll");
        return retval;
    }
    private void Form1_Load(object sender, EventArgs e)
    {
        Type custDataType = BuildDynamicTypeWithProperties();

        PropertyInfo[] custDataPropInfo = custDataType.GetProperties();
        foreach (PropertyInfo pInfo in custDataPropInfo)
        {
            Console.WriteLine("Property '{0}' created!", pInfo.ToString());
        }

        Console.WriteLine("---");
        // Note that when invoking a property, you need to use the proper BindingFlags -
        // BindingFlags.SetProperty when you invoke the "set" behavior, and 
        // BindingFlags.GetProperty when you invoke the "get" behavior. Also note that
        // we invoke them based on the name we gave the property, as expected, and not
        // the name of the methods we bound to the specific property behaviors.

        object custData = Activator.CreateInstance(custDataType);

        ((TestData)custData).data1 = "This Works";
        ((TestData)custData).data2 = "This Works 2";
        custDataType.InvokeMember("CustomerName", BindingFlags.SetProperty,
                                      null, custData, new object[] { "Joe User" });
        var list = new List<object>();

        /* var1.data1 = "Hello";
         var1.data2 = "World";
         list.Add(var1);*/
        list.Add(custData);
        dataGridView1.DataSource = list;

    }

    private void button1_Click(object sender, EventArgs e)
    {
        var test = dataGridView1.Rows[0].DataBoundItem;
    }
}

public class TestData
{
    public string data1 { get; set; }
    public string data2 { get; set; }
} 
lesyriad
  • 115
  • 1
  • 8
  • Can you not use `dynamic`? See https://stackoverflow.com/questions/5573856/binding-a-gridview-to-a-dynamic-or-expandoobject-object/6298704#6298704 – Dylan Nicholson Nov 30 '17 at 06:53
  • That may work in some instances however the data relies heavily on the object and methods in that object so there is no way for me to convert it to a datatable without a major code change (couple thousand lines) so I need to derive the base class and add the properties programmatically. – lesyriad Nov 30 '17 at 07:24

1 Answers1

0

Turns out by disabling autogeneratecolumns fixed it. It seems the datagridview was clearing my created columns and generating new ones from the datasource.

lesyriad
  • 115
  • 1
  • 8