AdamCKing

Hi

I am trying to work out an undo / redo scenario for my application. I have a roughly tree-shaped set of data and all the commands in my application generally modify or replace objects at points in this tree in a single way.

To this end I was intending to implement an undo item to be stored on my undo stack, which would hold a deep copy of the item prior to modification or replacement (call this foo), and a reference to the property which is being set to cause the item to change (call this bar), so when undoing, I could set bar = foo, and add a relevant entry to the redo stack.

I was therefore wondering (if that made any sense), if you can in some way hold a reference to a property in a variable Or any other pointers in the right direction!

Thanks in advance

Adam



Re: Visual C# General Reference to a property itself, not its value??

Brendan Grant

A reference to a property in a variable... that all depends...

A property itself is nothing but a gatekeeper for giving access to internal values within a class... when grabbing the value from property (even a reference type) you aren¡¯t grabbing a reference to the property, itself, but are being given a value from inside of it... the property only exists to control the way you access it.

You can technically have a reference to a property... but that is a part of reflection and can be used for example when you are doing dynamic calling of code at runtime (ie where you don¡¯t know the name of the property or the object that you¡¯ll be calling at compile time).

This property you want a reference to... what exactly does it contain The state of your larger object at a given point in time






Re: Visual C# General Reference to a property itself, not its value??

AdamCKing

Brendan

I appreciate what you have said about properties, that was how I understood them.

If it means anything to you, I am working in a theatrical scenario - the tree contains a list of Shows, each of which are made up of Cues (in an observable collection for wpf), each of which contains a collection of real-world objects and the movements made to them. This is at its simplest.

I suppose I am just being lazy, but there are a lot of different branches, each of which could change significantly at runtime, so either I create an enum so I can use a big case statement to determine where to copy my saved state object back to, or I store the reference to the property so I can do undoLocation = undoObject in some kind of dynamic fashion, where for example undoLocation represents Shows[1].Cues[2]

Don't know whether this info helps





Re: Visual C# General Reference to a property itself, not its value??

Brendan Grant

I think so... and since you are doing a deep copy you should be ok in this manor... rather than just having your undo tree reference the current state.




Re: Visual C# General Reference to a property itself, not its value??

boban.s

It depends on number of properties on the Cue and number of properties that can be changed. For example if your Cue have 100 properties, and all you can change is it location then a collection of another object containg just a reference of your object and information about location can be enough.






Re: Visual C# General Reference to a property itself, not its value??

AdamCKing

I am a little confused about what the conclusion is !





Re: Visual C# General Reference to a property itself, not its value??

OmegaMan

I have a suspiscion that this advice will come too late in your process; but here it goes. Make each object responsible for its own version history. Best to have this either as an interface or a common base class with virutal overrides that keeps the process consistent. Have a communication established with a change control manager object. When a change is made, the object informs the manager which intern informs all other objects to save state.

Keep a drumbeat of versions that occur whenever a change is made. When that signal comes in, either have the object make a delta of the change in words such as a "changed prop Text to 'abc'" or create a copy of the object which is stored.

As undo and redo's occur broadcast that message, then update the screen appropriately. If the memory constraints are not too much the object copy and storage is nice, otherwise a written delta change will have to be done.





Re: Visual C# General Reference to a property itself, not its value??

AdamCKing

Interesting ...

It is definitely not too late to take this route, my classes are barely formed.

Can I just clarify your suggested approach, as I understand it:

Assuming I have room to store the objects as history, which I think I do, and only allowing a single stepping of undo or redo:

Each object stores a static list of itself, with a change version identifier, to which a shallow copy is added to whenever that specific object is changed, (shallow since the children will remain referenced correctly even if changes are made ! )

In the event that I need to perform an undo, the undo controller sends a signal to all objects which are subscribed to it, dictating change version, and I copy the properties of the object at the change version entry (if it exists) into the current object. Also, for redo, the current state also gets put on the list with a change identifier, so redo can recall this change.

[EDIT: I think this bit is complete and utter rubbish, I can make the two cases below behave the same and undo using the same method]

If this would work, then that sounds great, the one problem I am left with is related to the way I need to deal with WPF, so the data can be bound and not have to refresh unnecessarily -

Imagine I have a cue loaded on screen (through some bindings), if I now want to make some changes, I could be doing one of 2 things -

1. I am making changes that I want to record into the current cue

2. I am making changes, which I want to record into a new cue, or overwrite another existing cue, and it is incidental that I am using the current cue as a starting point

The current way I was planning to deal with this, which i think would work with the my original undo method, is that when I start editing a cue, its parent (the show) would take a deep copy, and allow the program to make all the changes it wants to the current state (which would display on screen automatically with wpf binding), and in case 1 above, would keep these changes, (and probably discard the deep copy, since all the undo data is already present). In case 2, I would 'move' my changed cue to another position in the shows cue list, and replace the deep copy of the old cue where it previously was.

Somehow in my mind this doesn't seem compatible with this undo scenario, although I can't quite work out why!

[/EDIT]

Hope I haven't talked myself in circles, and that someone can decipher my problem!

Thanks.

As a sidenote, if I do need to store delta's then how would I make use of "Changed prop Text to 'abc'" when it comes to needing to perform an undo - surely at the very least I would need to actually store "Changed prop Text from 'xyz'", but even then how do I act on this information programatically





Re: Visual C# General Reference to a property itself, not its value??

OmegaMan

Because the data is hierarchical in nature, the storing and displaying are two very daunting tasks. (Sometimes I become master of the obvious <g>).

I can't tell you how to update the screen or show the differences. But I would surmise that the first run will not be optimized for the user experience. There are trade offs in each design you decide to take. Maybe limit how far or to what degree things can be undone and redone. In a similar vain, there are photographic softwares that just don't allow you to go back incrementally.

As to working with a delta, you will need to create a grammar that works within your system, is consistent and flexible enough to meet the needs.

In responding to this post, it got me thinking. There are all these design patterns out there...but where is the undo - redo pattern <g> Good luck; the posts have got you thinking and there may not be one true way of doing it...so experiment and see where it takes you. Post back when you know more.





Re: Visual C# General Reference to a property itself, not its value??

AdamCKing

Thanks OmegaMan, I shall try this route out and see where it gets me - I'm only really prototyping at the moment, so I can always go back and re-write it!

As for an undo, redo pattern - I'm sure there is a pattern in Gamma et al which claims to be useful for undo, but my copy is at work, and from memory it only really copes with simple situations!

I shall return if I succeed!





Re: Visual C# General Reference to a property itself, not its value??

OmegaMan

AdamCKing wrote:
I shall return if I succeed!


Good Luck Adam...we are all counting on you. <g>





Re: Visual C# General Reference to a property itself, not its value??

IsshouFuuraibou

In regards to your first idea, of the undo/redo stack just maintaining a deep copy and property info...

I would suggest that you look into what you can do with reflections, there's a class in System.Reflection called PropertyInfo that stores info based on the meta-data of a property and allows you to access parts of it (get, set, etc). I haven't looked that far into using it, but you may also need a reference to the instance that you need to perform the property on as well.





Re: Visual C# General Reference to a property itself, not its value??

Peter Ritchie

By properties, do you mean something like:

Code Snippet

int Number

{

get { return this.number;}

set { this.number = value;}

}

These properties are actually implemented as methods (get_Number() and set_Number()), so you can't have a "reference" to a property because it may not be backed by a reference type. In the above example the type is int, which would be boxed if you tried to convert it to a reference so you'd actually be undo to a temporary object.

Here's another example of a property:

Code Snippet

String FullName

{

get { return this.FirstName + this.LastName;}

set { String[] names = value.Split(' '); this.FirstName = names[0]; this.LastName = names[1];}

}

In this case the concept of assigning a value to reference to "undo" doesn't make sense because logic needs to be performed to change the FullName property.

If you want to support "undoing" of properties you'll need to be able to call the property set method.