Click here to Skip to main content
15,886,518 members
Please Sign up or sign in to vote.
5.00/5 (2 votes)
See more:
I have several objects that have a lot of fields (40+). Each object is slightly different.

In order to edit these values, I used binding to bind each field of each object to GUI TextBox items. This keeps the objects in memory and the GUI in sync.

Once the user has entered values I want to be able to save them so I serial the object and save it in a file (in XML format).

However when I de-serialize into a new object, the bindings are lost.

I searched for solutions but cloning solutions always create new objects. I do not want to create a new object as I lose the bindings.

I can write my own field by field copy method but it is error prone since there are so many fields.

I tried re-binding the newly created object (I did not want to have to do this) but it doesn't work anyway because there are already bindings associated with that object type.

What is the best practices method for de-serializing into an existing object so I do not lose the bindings and repopulate all the fields without having to write code to manually copy each field?

Thanks
Posted

Hi,

My experience of reflection is limited, however if that's the way you want to go, might I suggest trying:


// Get class
Type myType = typeof(myClass);

// Get Properties of that class
PropertyInfo[] myClassProperties = myType.GetProperties();

 MethodInfo[] myClassMethods = myType.GetMethods(); 


You iterate through these lists and access the information that you need.

Or if you want to get the class name at runtime you can try:
Type myType = typeof(SomeType);//This type must exist in the assembly you want to examine

// Search in the correct assembly that contains all the classes you want
Assembly myAssempbly = Assembly.GetAssembly(myType);

Type myType = myAssempbly.GetType(desiredClass);


Hope this helps

Laurence
 
Share this answer
 
Comments
Max Power Sr 10-Feb-11 10:38am    
Thanks!

First off, I don't necessarily want to go with reflection. I am just looking for some solution to my problem.

Now that I have a list of methods, how do I know which method to call and how do I match which field (from the new object I created from deserialization) that goes with it? If I have to search for specific method names, then it defeats the purpose of trying to write generic code to update all of my fields.

I have used the code you posted and I am looking at the results to see if there is a way to do what I want.

Thanks again for the help
Laurence1234 10-Feb-11 10:52am    
No Problem :) If the answer leads to a solution please vote for my answer.

I see your problem now, while it is possible to get a specific method by calling:

myType.GetMethod(methodStringName);

I can see why you would want to avoid that.

As you stated in your comment in the above post you are having trouble returning the accessors. The List of properties should return this information for you.

Also, when you say "which method to call" are you intending on invoking that method once you find it? If so, that is possible using the Invoke method inside the MethodInfo class.

Cheers
Max Power Sr 10-Feb-11 11:17am    
Thanks to both of you for the help. I learned a lot today.

I should have rephrased the question at a higher level and not pushed this in the direction of reflection. However, here we are lol

This is what I did and it works. I am not sure this is the best/safest solution but here goes...



// Get class
Type myType = typeof(Coefficients);

// Get Properties of that class
PropertyInfo[] myClassProperties = myType.GetProperties();

MethodInfo[] myClassMethods = myType.GetMethods();

foreach (MethodInfo mi in myClassMethods)
{
String fullMethodName = mi.Name;
char[] seps = { '_' };
String[] methodName = fullMethodName.Split(seps);
if (methodName[0] == "set")
{
string newMethodName = "m_" + methodName[1];
FieldInfo fi = myType.GetField(newMethodName, BindingFlags.NonPublic | BindingFlags.Instance);
object[] o = {fi.GetValue(rhs)};
mi.Invoke(this, o);
}
}
Laurence1234 10-Feb-11 11:29am    
Hey man,
No problem :D Just so happens I was working on some reflection the other day, so it's still fresh.

I see what you've done there; you're looking for a certain method, that starts with "set" and creating a new method name, which you then invoke.

How will you know that method will be there?

Also, what is the variable 'rhs' ?

If you could describe what you're doing there that would be great.

Thanks

Laurence
Max Power Sr 10-Feb-11 11:52am    
Oops. There were two lines ahead of what I posted above.

public void CopyInto(Coefficients rhs)
{

The "this" object is getting a copy of the fields in rhs. "This" is of type Coefficients. The name "rhs" came from the example that dasblinkenlight posted. Which was a copy constructor and would have resulted in code that had a right hand side.

In my object I have declared some fields:
string m_Coeff0, m_Coeff1, etc...

Then I wrote some methods, such as:

[System.ComponentModel.Bindable(true)]
public string Coeff0
{ get { return m_Coeff0; } set { m_Coeff0 = value; OnPropertyChanged("Coeff0"); } }

This creates methods set_Coeff0 and get_Coeff0. So I know they will exist. The methods have to be called to update the fields so that the TextBox GUI items that are sync'd via a call to DataBinding.Add will be updated.

What am I trying to do?

I have a DSP target that is running control algorithms. Each controller will have 40+ parameters that can be changed to affect the controller. There are at least 5 controllers running on the DSP.

So I am writing a PC app to allow someone to load/save these parameters from disk and send them to the target (via CAN bus). The user can also change the parameters. The GUI is a tab control, with each tab having 40 or so TextBox items.

I needed a way to synchronize the on screen GUI text box items with values in memory. That is why I use DataBinding. For each TextBox item I add to the GUI, I set the "Tag" property to the same name so I can bind the GUI objects to the appropriate Get/Set method automatically without having to write DataBinding.Add 40+ times.

If I had to manually copy, set, configure, etc... each parameter the amount of work, and chance for copy/paste type bugs, increases. I am looking for ways to automate.

This was all pretty straightforward up until I read the data from disk and the deserialize method creates a new object. You lose the DataBinding. I could have just DataBinding.Add again but it throws an exception because the TextBox items still are bound to the old data object. You can delete them but it just seemed like I should be able to copy objects and not lose the DataBinding lol

Again, thanks for the help!
This may not be the best way to handle the problem, but if you need a field-by-field copy, you could use reflection to write something similar to this guy's copy constructor[^]. The idea is that instead of writing forty lines like this
this.Property123 = other.Property123;
you would let the reflection do the job for you. This solution survives changes to the structure of the class, easing your maintenance worries.
 
Share this answer
 
v2
Comments
Max Power Sr 10-Feb-11 10:04am    
The code is nice and simple. I had seen reflection as a solution but the examples I saw were much more complicated. Thanks!

I did not implement the code as a copy constructor as I do not want to create a new class. I just use this code to copy the fields from a new class into my existing class.

I had to use BindingFlags.NonPublic only because I have a member defined:

public event PropertyChangedEventHandler PropertyChanged;

and I don't want to overwrite that.


The problem I am having now is that after I load the new serialzed data into my existing object, the binded TextBox objects are not being updated. This is because reflection does not go through the normal get/set methods.


Thanks
dasblinkenlight 10-Feb-11 10:34am    
Actually, the link I posted was more a hint than a solution: I understood from your original post that you did not need a new object. One of the things you should do is to switch from setting fields to calling property setters. Otherwise, your bindings will not know that they need to update.
If instead of GetFields you use GetProperties, you should be able to accomplish what you need (PropertyInfo objects let you access property getters and setters as MethodInfo objects; you can invoke them through reflection).
Laurence1234 10-Feb-11 10:09am    
Hi,

If you have a look at my solution below, I think I can help to solve that problem and return the list of properties.

Thanks

Laurence

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900