How can I keep object from passing to another form? - c#

I'm using ObjectListView and the object I'm adding to it is a custom Class that I've built for it.
My Class contains information for doing calculations. I want to allow users to be able to edit calculations they've already made.
I've tried pulling the object from the ObjectListView with the following different code:
Customer customer = (Customer)listCustomers.SelectedItem.RowObject;
Customer customer = (Customer)listCustomers.GetSelectedObject();
Customer customer = (Customer)listCustomers.SelectedObject;
All of those methods result in the customer to become that object. The problem I'm facing though, is if I change any of the values of that class, such as the following code, it reflects the change in that object in the ObjectListView:
customer.TotalValue += 50;
And even if I run those calculations on another form, by transferring that information via:
EditCustomer editForm = new EditCustomer(customer)
editForm.Show();
It still changes the object in the ObjectListView.
What I'm wondering, is how can I extract that object, and allow me to edit the customer object, while not changing the object in the ObjectListView?

Your customer variable is a reference to the object stored in your ObjectListView, so when you modify customer, the change is reflected in the underlying object it is referencing. When you pass customer to a different form, you are passing the reference, still pointing to the same underlying object, so that object can then be modified through that reference, even from a different form.
To get the behavior you want, you need to clone your object, making a completely separate copy of it, and then making changes to the copy will not impact the original.
Check here for information on cloning objects.

Related

Adding contextual data to a shared object

I'm trying to come up with a generic model for associating some contextual data with an object in C#. I have built a caching system that can be described as follows...
Background Story -> The cache is a singleton implementation that provides "readonly" access to frequently requested information that is part of a custom CMS implementation that I use for various asp.net applications. I update the data via a desktop application I have written and the next time the web server loads the cache my changes are reflected to visitors.
My cache adheres to the following...
Every object has a unique id
Any object can be associated with any other object by an id mapping defined in an association table
No matter how many associations to a particular object exist, only one instance of that object is loaded into the cache.
For example...Object A might associate to a collection of Object C's. Similarly Object B might also associate to a collection of Object C's. If one were to request an Object C with id 23 from an instance of Object A and then request an Object C with id 23 from Object B, they would get a handle to the same instance of Object C.
I now have some data to add into the picture but the data does not belong to Object A by itself and it does not belong to Object C by itself. The data is information specific to the association of Object A with Object C.
My First Idea: Keep the additional data separate from Object C since it doesn't actually belong to Object C by itself. Maintain this information within Object A and allow it to be looked up in a Dictionary. I don't like the way the data has to be accessed in this approach. I would rather have direct access to the additional data via Object C or a derived class for binding purposes and ease of use.
My Second Idea: Create a derived class from Object C (call it Object D) that includes the additional contextual data and provides properties for easy access. This addresses the binding and gives me the ease of use that I was looking for. My problem with this approach is that now my Object A is referring to a collection of Object D's and I am required to break my above model by duplicating the entirety of Object A's data just so that I can append some extra association information.
What I would really like is to continue having only one instance of Object C for a given id and append some contextual data and properties that can be easily accessed in the appropriate context. Can this be done? I'm also open for any other suggestions here! I want my solution to be generic and sound so I can forget about it and not have that constant itch to go back and find a better solution.
The Objec C instances should hold there own data. Of course you can store the "path" in it via what the object was retrieved from the cache (via Object A or Object B), but storing this kind of information in the object, modifies the object, so if it were to be retrieve via another "path", the information will be overrwritten.
A solution could be to clone object C every time it is retrieved from the cache and store your "path" in it, or store your extra data if it came via Object A?
This way, all objects inside your cache are shared as requested, but stand alone once outside the cache.
I ended up going with my second idea. Object D became a special type of object that has it's own properties/members/methods but also has a property that returns an Object C. Object D must implement a specific interface to be identified by my caching algorithm. I updated my caching system to ensure that if the Object C returned by the property has already been loaded, that one is returned instead of loading up an additional copy from the db.

Dynamically binding data contained within an object to labels in a windows form

I have the following data and objects in my program.
A DynamicObjectContainer that contains the following objects.
MeasurementParameters : DataContainer (DataContainer is the base class)
This MeasurementParameters object has many public properties, whose names I know only during runtime. I have also set up internal wiring in the DataContainer base class such that, I can access the values of the properties contained in the MeasurementParameters class using an easy to use interface.
Ex : Say I have a property in MeasurementParameters named as "pumpspeed" (type string). I can access the value of that property using this function.
MeasurementParameters.GetStringValue("pumpspeed");
I have achieved this by creating lists of delegates internally in the DataContainer object using reflection during construction of the object. (This is a one time thing.)
So far so good.
Now I am stuck at the point where I want to display these values within MeasurementParameters in a windows form.
Since I only know the property names at runtime, I have to provide the user with some method to map the property names (defined only by him in a script file) to the fixed labels within the form. So the user saves the mapping data to the table in the following format.
Entry : "pumpspeed" "label22"
I want a fast and efficient method to fetch this mapping from the database, fetch required data from the MeasuremetParameters object and display it in the windows form.
NOTE : If this is a one time operation, I have many solutions. The problem is two fold.
There are a huge number of properties in the MeasurementParameters (at around 200)
The MeasurementParameters object contains functions that update it's properties continuously. SO My windows form has to call those functions to update the MeasurementParameters object data, fetch the data and display it in the correct labels.
ALSO, this should happen in cycles of around 2 -3 times a second. (ideally)
Can anyone help me in architecting a solution for this?? A general object structure and relationship advice will also be helpful to me.
I can post the code I am using if required.
Not seeing a huge problem here
So you have Table ObjectID, PropertyName, ControlName
On opening the form / selecting the object, query them out
Build a Dictionary Keyed by PropertyName with a Value of the Label (looked up by the name of teh control from the query MyForm.Controls.FindByName(Somename). Add an OnPropertyChangedEvent to your class that throws up the name of the Property in event args then add a handler on the form
Mappings[e.PropertyName].Text = Object[e.PropertyName].GetStringValue;
Might have to twidlle with it to deal with say display controls that aren't Labels, or Panels on the Form, but it should just batter away.

Populating A New Object With Existing Objects Data

I have a service that is returning a custom object called "UserSettings" In my application I want to add more properties to the "UserSettings" object so I created a new object called "MyUserSettings" that inherits from "UserSettings" now I want to populate my new object with the existing data held in "UserSettings" and the new data I have for my new properties. I do not want to have to map each property one by one to the same property in the new object like this..
_MyUserSettings.Name=_UserSettings.Name;
Is there a way or better approach to what I am doing to populate ALL the properties of the existing object into my new object in one shot??
Yes, you can use Copy Constructor pattern. It would give you an other benefit - you do not need public property setters so object becomes immutable.
public MyUserSettings(UserSettings baseSettings)
{
// TODO: set all properties
}
Unfortunately this is the only way, however, the specific mechanism can change. There are a numerous ways (not listing them all):
Copy constructor, that takes an item and does this manual copying of fields across.
Use reflection to have a more generic mechanism of achieving the same.
Use something like AutoMapper.
They all boil down to pretty much doing the same thing.
If the UserSettings is actually a MyUserSettings then you can simply cast it:
var mySettings = (MyUserSettings)settings;
However, this will fail if UserSettings is really UserSettings.

C# and ASP.NET custom property attributes and determining if properties changed

I am working on a project where we want to keep a history of a particular object. On save I want a method on the object that will determine if it has changed so that I can call a method to save its current state to history. E.g. I populate a form from an object the user makes changes (or possibly not) and submits the from. I want to take my original object and a copy of that object that has been updated from the form and determine if it has changed at all. Additionally I may decide at some point that certain properties don't matter (e.g. if Name changes I won't track it).
I'm thinking the easiest/most flexible way to accomplish this would be if I could give the properties I care about a custom attribute [ChangeTracked] and then I could use reflection to get a list of all properties with that attribute and loop through them comparing A.property == B.property to determine if any have changed.
Would this work? Is there a significantly better/easier way to handle this, like some sort of built in method you can add to an object to determine if the values of any properties have changed? Whatever the solution some psudo code would be appreciated. Just as a point of clarification the solution needs to determine if the value I care about has actually changed not just if it has been assigned since it was created i.e. if I set Name="bob" and it was already "bob" before my assignment this does not count as a change.
It ain't fancy, but this is the tried and true brute force method. Just add a private property to the object named IsDirty. For properties that you want to track, just add IsDirty=True to the property Set routine. For more complicated "do I care" rules, just code them into the property set.
The page button's click event can fire a Save event that writes all the values from the textboxes and dropdowns into the object properties, then calls the object Save method, which tests the IsDirty property before doing anything.
One possible method would be to add a deep copy of the object as a private property of the object when it is loaded. (One method of deep copy)
On save you can compare the copy object to your "live" object to see if any changes have occurred.

Persisting object changes from child form to parent form based on button press

I have created a form that is used for both adding and editing a custom object. Which mode the form takes is provided by an enum value passed from the calling code. I also pass in an object of the custom type. All of my controls at data bound to the specific properties of the custom object. When the form is in Add mode, this works great as when the controls are updated with data, the underlying object is as well. However, in Edit mode, I keep two variables of the custom object supplied by the calling code, the original, and a temporary one made through deep copying. The controls are then bound to the temporary copy, this makes it easy to discard the changes if the user clicks the Cancel button. What I want to know is how to persist those changes back to the original object if the user clicks the OK button, since there is now a disconnect because of the deep copying. I am trying to avoid implementing a internal property on the Add/Edit form if I can. Below is an example of my code:
public AddEditCustomerDialog(Customer customer, DialogMode mode)
{
InitializeComponent();
InitializeCustomer(customer, mode);
}
private void InitializeCustomer(Customer customer, DialogMode mode)
{
this.customer = customer;
if (mode == DialogMode.Edit)
{
this.Text = "Edit Customer";
this.tempCustomer = ObjectCopyHelper.DeepCopy(this.customer);
this.customerListBindingSource.DataSource = this.tempCustomer;
this.phoneListBindingSource.DataSource = this.tempCustomer.PhoneList;
}
else
{
this.customerListBindingSource.DataSource = this.customer;
this.phoneListBindingSource.DataSource = this.customer.PhoneList;
}
}
You could always add a function to your object (Customer), either as "Copy(Customer cust)" or "Update(Customer cust)" and consume the changes that way.
The other way would be to have a wrapper class around Customer EditableCustomer, which takes a customer object in its constructor EditableCustomer(Customer root) and uses that to hold the changes. In the final event just call a function like "UpdateRoot()" and populate the changes back to the original customer, failing to call this will be the same as a discard.
You wont be able to use deep copies directly but this will allow you to control this type of situation, and actually allow you to control both edits and undo's dynamically.

Categories