WPF - basic data binding and "Save" x "Cancel changes"
-
I have done this by using buffer objects. Essentially when the control starts create a copy of the model. Then instead of the View Model updating the "Raw" model object it updates the "Buffer" object. When they click save you load the buffer's data in the original object's data. If they click cancel you need to do nothing (cause you never changed the raw object that other objects have references to)
Computers have been intelligent for a long time now. It just so happens that the program writers are about as effective as a room full of monkeys trying to crank out a copy of Hamlet.
Not a good idea to re-invent the wheel here. You should stick with IEditableObject since that is the "standard" way of doing it. Doing it the "standard" way has the benefit of clean integration with controls.
-
Not a good idea to re-invent the wheel here. You should stick with IEditableObject since that is the "standard" way of doing it. Doing it the "standard" way has the benefit of clean integration with controls.
Actually you are not 'Re-inventing" anything. For one, to use the IEditableObject you have to "Impliment" the interface. This means you must change your base object... Maybe the standard, but if the object already exists and does not have that interface, implimenting it now is work. To impliment a buffer object you need only cycle through the props (or do it manually if you only need 'some')
private void LoadModel(T loadFrom, T loadInto)
{
Type t = typeof(T);
var props = t.GetProperties();
foreach (var prop in props)
{
MethodInfo setter = prop.GetSetMethod(true);
if (setter != null)
{
setter.Invoke(loadInto, new object[] { prop.GetValue(loadFrom, null) });
}
}
}Now you can pass any object that are the same type and load from one to the other (assumming you use public props.. which well you should be using if you are doing things the 'standard' way. So what are we "Re-inventing" here?
Computers have been intelligent for a long time now. It just so happens that the program writers are about as effective as a room full of monkeys trying to crank out a copy of Hamlet.
-
Actually you are not 'Re-inventing" anything. For one, to use the IEditableObject you have to "Impliment" the interface. This means you must change your base object... Maybe the standard, but if the object already exists and does not have that interface, implimenting it now is work. To impliment a buffer object you need only cycle through the props (or do it manually if you only need 'some')
private void LoadModel(T loadFrom, T loadInto)
{
Type t = typeof(T);
var props = t.GetProperties();
foreach (var prop in props)
{
MethodInfo setter = prop.GetSetMethod(true);
if (setter != null)
{
setter.Invoke(loadInto, new object[] { prop.GetValue(loadFrom, null) });
}
}
}Now you can pass any object that are the same type and load from one to the other (assumming you use public props.. which well you should be using if you are doing things the 'standard' way. So what are we "Re-inventing" here?
Computers have been intelligent for a long time now. It just so happens that the program writers are about as effective as a room full of monkeys trying to crank out a copy of Hamlet.
Lots of problems with your solution: 1) reflection is slow 2) only supports public, simple properties... what about private and/or complex properties? what about nested properties? 3) reference objects will get set in both copies, no? 4) will not work with controls that require IEditableObject
-
Lots of problems with your solution: 1) reflection is slow 2) only supports public, simple properties... what about private and/or complex properties? what about nested properties? 3) reference objects will get set in both copies, no? 4) will not work with controls that require IEditableObject
Now you are being silly...
SledgeHammer01 wrote:
reflection is slow
Soo how do you expect the IEditableObject to do this work??? (if you read Pete's blog he even says that his EditableObject uses reflection....). Also reflection is not that slow. I mean if this has to occur over and over (like 100's of time in seconds.. why would this be though???) and the object is very large (consider refactoring) you may want a different option (again.. I do not see how the IEditableObject solves this.. it is merely an interface, NOT an implimentation of it).
SledgeHammer01 wrote:
only supports public, simple properties... what about private and/or complex properties? what about nested properties?
So were you planning on binding some UI elements to private properties??? Or 'Complex' properties as you put it? If so, the logic is already there... Because you already implimented it. Also, if you want it to support private fields you can certainly impliment that (I did not because I had no need for it)
SledgeHammer01 wrote:
reference objects will get set in both copies, no?
Yes (if you set the property from the getter of the other object it will pass the objects reference... Unless of course it is value based but who cares as that is value based and you will re-load)
SledgeHammer01 wrote:
will not work with controls that require IEditableObject
Do you really think the OP requires this anywhere??? On a last point, even if you provide a nice implimentation of IEditableObject (that somehow does NOT use reflection), you are now forcing a base class on an object for simple functionality (see post above.. what like 10 lines of code).
Computers have been intelligent for a long time now. It just so happens that the program writers are about as effective as a room full of monkeys trying to crank out a copy of Hamlet.
-
Now you are being silly...
SledgeHammer01 wrote:
reflection is slow
Soo how do you expect the IEditableObject to do this work??? (if you read Pete's blog he even says that his EditableObject uses reflection....). Also reflection is not that slow. I mean if this has to occur over and over (like 100's of time in seconds.. why would this be though???) and the object is very large (consider refactoring) you may want a different option (again.. I do not see how the IEditableObject solves this.. it is merely an interface, NOT an implimentation of it).
SledgeHammer01 wrote:
only supports public, simple properties... what about private and/or complex properties? what about nested properties?
So were you planning on binding some UI elements to private properties??? Or 'Complex' properties as you put it? If so, the logic is already there... Because you already implimented it. Also, if you want it to support private fields you can certainly impliment that (I did not because I had no need for it)
SledgeHammer01 wrote:
reference objects will get set in both copies, no?
Yes (if you set the property from the getter of the other object it will pass the objects reference... Unless of course it is value based but who cares as that is value based and you will re-load)
SledgeHammer01 wrote:
will not work with controls that require IEditableObject
Do you really think the OP requires this anywhere??? On a last point, even if you provide a nice implimentation of IEditableObject (that somehow does NOT use reflection), you are now forcing a base class on an object for simple functionality (see post above.. what like 10 lines of code).
Computers have been intelligent for a long time now. It just so happens that the program writers are about as effective as a room full of monkeys trying to crank out a copy of Hamlet.
Collin Jasnoch wrote:
Soo how do you expect the IEditableObject to do this work??? (if you read Pete's blog he even says that his EditableObject uses reflection....). Also reflection is not that slow. I mean if this has to occur over and over (like 100's of time in seconds.. why would this be though???) and the object is very large (consider refactoring) you may want a different option (again.. I do not see how the IEditableObject solves this.. it is merely an interface, NOT an implimentation of it).
Are you familiar with how IEditableObject works? You just implement 3 standard methods any way you want. If I was doing it? Well, I'd have my base object implement ICloneable and use that to clone the object properly. That has the benefit of being another standard interface that other people might want to use and is more performant then reflection. You *COULD* implement your ICloneable to copy the object with reflection, but thats just plain silly. I highly suggest you run some performance benchmarks on reflection and see just how slow it is.
Collin Jasnoch wrote:
So were you planning on binding some UI elements to private properties??? Or 'Complex' properties as you put it? If so, the logic is already there... Because you already implimented it. Also, if you want it to support private fields you can certainly impliment that (I did not because I had no need for it)
OK, adding support for private properties was just a minor nitpick and that is trivial... but yeah, I'm binding to a complex property right now as I type this. How is your code going to handle: Dictionary<string, Dictionary<string, CMTInfo[]>> ? Thats a valid "complex" type that I'm binding to a TreeView.
Collin Jasnoch wrote:
Do you really think the OP requires this anywhere???
Yeah, cuz, NOBODY uses the data grid :). Data grid used IEditableObject as one example of a popular control that uses it.
Collin Jasnoch wrote:
On a last point, even if you provide a nice implimentation of IEditableObject (that somehow does NOT use reflection), you are now forcing a base class on an object for simple functionality (see post above.. what like 10 lines of code).
Whats your point? Anything you bind to in the UI needs to implement INotifyPropertyChanged / INotify
-
Collin Jasnoch wrote:
Soo how do you expect the IEditableObject to do this work??? (if you read Pete's blog he even says that his EditableObject uses reflection....). Also reflection is not that slow. I mean if this has to occur over and over (like 100's of time in seconds.. why would this be though???) and the object is very large (consider refactoring) you may want a different option (again.. I do not see how the IEditableObject solves this.. it is merely an interface, NOT an implimentation of it).
Are you familiar with how IEditableObject works? You just implement 3 standard methods any way you want. If I was doing it? Well, I'd have my base object implement ICloneable and use that to clone the object properly. That has the benefit of being another standard interface that other people might want to use and is more performant then reflection. You *COULD* implement your ICloneable to copy the object with reflection, but thats just plain silly. I highly suggest you run some performance benchmarks on reflection and see just how slow it is.
Collin Jasnoch wrote:
So were you planning on binding some UI elements to private properties??? Or 'Complex' properties as you put it? If so, the logic is already there... Because you already implimented it. Also, if you want it to support private fields you can certainly impliment that (I did not because I had no need for it)
OK, adding support for private properties was just a minor nitpick and that is trivial... but yeah, I'm binding to a complex property right now as I type this. How is your code going to handle: Dictionary<string, Dictionary<string, CMTInfo[]>> ? Thats a valid "complex" type that I'm binding to a TreeView.
Collin Jasnoch wrote:
Do you really think the OP requires this anywhere???
Yeah, cuz, NOBODY uses the data grid :). Data grid used IEditableObject as one example of a popular control that uses it.
Collin Jasnoch wrote:
On a last point, even if you provide a nice implimentation of IEditableObject (that somehow does NOT use reflection), you are now forcing a base class on an object for simple functionality (see post above.. what like 10 lines of code).
Whats your point? Anything you bind to in the UI needs to implement INotifyPropertyChanged / INotify
SledgeHammer01 wrote:
Are you familiar with how IEditableObject works? You just implement 3 standard methods any way you want. If I was doing it? Well, I'd have my base object implement ICloneable and use that to clone the object properly. That has the benefit of being another standard interface that other people might want to use and is more performant then reflection. You *COULD* implement your ICloneable to copy the object with reflection, but thats just plain silly.
Yep. And it seems quite pointless in my mind. If I have a UI exposing data, 99/100 times I am already in Edit mode. Rarely I have seen systems use the Optimistic Locking approach [^] What does this have to do with it you ask? Well if I already "Locked" my data I have editabality. Now it is just about the user wanting the data to persist. I.e. "BeginEdit" and "EndEdit" are totally pointless. The only thing the interface provides is "CancelEdit"... Who cares? Why do we need an interface for cancel?? The solution I provided doesn't need any interface and is not coupled to anything. Yes, it uses reflection. if you think that is too slow for the system use a different way. You meantion IClone.. Again an interface NOT an implimentation. Most IMPLIMENTATIONS of it will use reflection. If not then have fun maintaining that code. Honestly if you think reflection is so bad why are you even in the WPF forums (how do you think most of the WPF features work? Oh right.. Magik ;))
Computers have been intelligent for a long time now. It just so happens that the program writers are about as effective as a room full of monkeys trying to crank out a copy of Hamlet.
-
Collin Jasnoch wrote:
Soo how do you expect the IEditableObject to do this work??? (if you read Pete's blog he even says that his EditableObject uses reflection....). Also reflection is not that slow. I mean if this has to occur over and over (like 100's of time in seconds.. why would this be though???) and the object is very large (consider refactoring) you may want a different option (again.. I do not see how the IEditableObject solves this.. it is merely an interface, NOT an implimentation of it).
Are you familiar with how IEditableObject works? You just implement 3 standard methods any way you want. If I was doing it? Well, I'd have my base object implement ICloneable and use that to clone the object properly. That has the benefit of being another standard interface that other people might want to use and is more performant then reflection. You *COULD* implement your ICloneable to copy the object with reflection, but thats just plain silly. I highly suggest you run some performance benchmarks on reflection and see just how slow it is.
Collin Jasnoch wrote:
So were you planning on binding some UI elements to private properties??? Or 'Complex' properties as you put it? If so, the logic is already there... Because you already implimented it. Also, if you want it to support private fields you can certainly impliment that (I did not because I had no need for it)
OK, adding support for private properties was just a minor nitpick and that is trivial... but yeah, I'm binding to a complex property right now as I type this. How is your code going to handle: Dictionary<string, Dictionary<string, CMTInfo[]>> ? Thats a valid "complex" type that I'm binding to a TreeView.
Collin Jasnoch wrote:
Do you really think the OP requires this anywhere???
Yeah, cuz, NOBODY uses the data grid :). Data grid used IEditableObject as one example of a popular control that uses it.
Collin Jasnoch wrote:
On a last point, even if you provide a nice implimentation of IEditableObject (that somehow does NOT use reflection), you are now forcing a base class on an object for simple functionality (see post above.. what like 10 lines of code).
Whats your point? Anything you bind to in the UI needs to implement INotifyPropertyChanged / INotify
SledgeHammer01 wrote:
OK, adding support for private properties was just a minor nitpick and that is trivial... but yeah, I'm binding to a complex property right now as I type this. How is your code going to handle:
Dictionary<string, Dictionary<string, CMTInfo[]>>Yep you are right... You will need to do something speacial there (as you would with IClone as well). You are now just getting into the topic of Deep copy versus shallow copy. Not to complicated to handle with a little extra logic. Sure you can impliment IClonable.... But again YOU must impliment. Telling someone to use an interface as the solution will not work. An interface provides nothing, except the "interface". The implimentation needs to be provided since that is what the OP cares about. Again, if you feel reflection is not a valid solution by all means post something else but dont' ridcule my IMPLIMENTATION solution because I do not call out Interfaces as they are not actually a solution but an "interface" to a solution. Yes, Pete provides an implementation of IEditableObject (which uses reflection mind you). So he can say it is good etc. etc. You however are debating about how the Interface MUST be used and then saying reflection should not be the implimentation of its usage because it is too slow. Well be conustructive and provide an implimentation that does not use it.
Computers have been intelligent for a long time now. It just so happens that the program writers are about as effective as a room full of monkeys trying to crank out a copy of Hamlet.
-
SledgeHammer01 wrote:
OK, adding support for private properties was just a minor nitpick and that is trivial... but yeah, I'm binding to a complex property right now as I type this. How is your code going to handle:
Dictionary<string, Dictionary<string, CMTInfo[]>>Yep you are right... You will need to do something speacial there (as you would with IClone as well). You are now just getting into the topic of Deep copy versus shallow copy. Not to complicated to handle with a little extra logic. Sure you can impliment IClonable.... But again YOU must impliment. Telling someone to use an interface as the solution will not work. An interface provides nothing, except the "interface". The implimentation needs to be provided since that is what the OP cares about. Again, if you feel reflection is not a valid solution by all means post something else but dont' ridcule my IMPLIMENTATION solution because I do not call out Interfaces as they are not actually a solution but an "interface" to a solution. Yes, Pete provides an implementation of IEditableObject (which uses reflection mind you). So he can say it is good etc. etc. You however are debating about how the Interface MUST be used and then saying reflection should not be the implimentation of its usage because it is too slow. Well be conustructive and provide an implimentation that does not use it.
Computers have been intelligent for a long time now. It just so happens that the program writers are about as effective as a room full of monkeys trying to crank out a copy of Hamlet.
If its inside the object itself, I would just do a prop by prop copy. Expression trees are 1000x faster then reflection for get/set, but the startup cost is more, so those are more useful when you are getting the same prop over and over and can cache the lambda.
-
If its inside the object itself, I would just do a prop by prop copy. Expression trees are 1000x faster then reflection for get/set, but the startup cost is more, so those are more useful when you are getting the same prop over and over and can cache the lambda.
Some times I feel programmers get a bit carried away with implementing code. Building a dragster to take a midnight stroll around town for instance is a bit overkill. The poster simply asked for a process that would work for his issue. It seems both of you have valid ways on how to approach this but one thing remains which method is simpler to comprehend. Giving an explanation to some one that is more complex than he requires, while sound in theory, may not be the right solution for his particular issue. I'm still a big fan of if it works to fix the problem use it. You don't regrow an entire leg to fix a small cut you slap a band-aid on it. I know you can argue that implementing the wrong programming techniques can potentially lead to problems in the future, but you can run into issues even using the correct ones. Now I apologize for derailing this gentleman's thread but after reading this I became even more confused as to how to accomplish the original question. I can just imagine that he may be just as confused. Sometimes it helps to remember that people post here because they don't have the answers, and we need to remember not everyone can comprehend at the same level.
-
Some times I feel programmers get a bit carried away with implementing code. Building a dragster to take a midnight stroll around town for instance is a bit overkill. The poster simply asked for a process that would work for his issue. It seems both of you have valid ways on how to approach this but one thing remains which method is simpler to comprehend. Giving an explanation to some one that is more complex than he requires, while sound in theory, may not be the right solution for his particular issue. I'm still a big fan of if it works to fix the problem use it. You don't regrow an entire leg to fix a small cut you slap a band-aid on it. I know you can argue that implementing the wrong programming techniques can potentially lead to problems in the future, but you can run into issues even using the correct ones. Now I apologize for derailing this gentleman's thread but after reading this I became even more confused as to how to accomplish the original question. I can just imagine that he may be just as confused. Sometimes it helps to remember that people post here because they don't have the answers, and we need to remember not everyone can comprehend at the same level.
As I indicated to the other poster, it is (potentially) important to implement STANDARD interfaces rather then employing band-aid fixes. Just like WPF relies on you implementing INotifyPropertyChanged, some aspects of it rely on you implementing IEditableObject. The discussion got derailed on how the internals should work rather then the outside of the black box.
-
As I indicated to the other poster, it is (potentially) important to implement STANDARD interfaces rather then employing band-aid fixes. Just like WPF relies on you implementing INotifyPropertyChanged, some aspects of it rely on you implementing IEditableObject. The discussion got derailed on how the internals should work rather then the outside of the black box.
Thank you all guys, only now did I get the time to read all posts. To summarize what I learned: 1) .NET ships with IEditableObject interface which I am advised to implement in such situations 2) the implementation may use reflection, expression trees (not sure I quite understand this), or can be manually typed out for a particular class 3) the implementation (in any case) does nothing other that store a copy of the data for possible rollback later 4) .NET framework itself provides no extra advantage of using IEditableObject (except data grid and maybe few other specific controls) - a typical window with textboxes and checkboxes for data is unaware of IEditableObject and I must manually call BeginEdit, CancelEdit etc. Therefore - if I just make the copy but not as an implementation of IEditableObject, it'll work the same, but it is not advisable because it is not standard practice. Let me please know if I understand this correctly. H.
-
Thank you all guys, only now did I get the time to read all posts. To summarize what I learned: 1) .NET ships with IEditableObject interface which I am advised to implement in such situations 2) the implementation may use reflection, expression trees (not sure I quite understand this), or can be manually typed out for a particular class 3) the implementation (in any case) does nothing other that store a copy of the data for possible rollback later 4) .NET framework itself provides no extra advantage of using IEditableObject (except data grid and maybe few other specific controls) - a typical window with textboxes and checkboxes for data is unaware of IEditableObject and I must manually call BeginEdit, CancelEdit etc. Therefore - if I just make the copy but not as an implementation of IEditableObject, it'll work the same, but it is not advisable because it is not standard practice. Let me please know if I understand this correctly. H.
Basically, that's spot on. Although it also ships with IEditableCollectionView which you may want to take advantage off if you are adding to collections.
Forgive your enemies - it messes with their heads
My blog | My articles | MoXAML PowerToys | Mole 2010 - debugging made easier - my favourite utility
-
Actually you are not 'Re-inventing" anything. For one, to use the IEditableObject you have to "Impliment" the interface. This means you must change your base object... Maybe the standard, but if the object already exists and does not have that interface, implimenting it now is work. To impliment a buffer object you need only cycle through the props (or do it manually if you only need 'some')
private void LoadModel(T loadFrom, T loadInto)
{
Type t = typeof(T);
var props = t.GetProperties();
foreach (var prop in props)
{
MethodInfo setter = prop.GetSetMethod(true);
if (setter != null)
{
setter.Invoke(loadInto, new object[] { prop.GetValue(loadFrom, null) });
}
}
}Now you can pass any object that are the same type and load from one to the other (assumming you use public props.. which well you should be using if you are doing things the 'standard' way. So what are we "Re-inventing" here?
Computers have been intelligent for a long time now. It just so happens that the program writers are about as effective as a room full of monkeys trying to crank out a copy of Hamlet.
I got to give you 5 as this is exactly the approach I used (before I ran across IEditable). I copy the object in the selected property change and bind the editable## to the UI. Chucked the copy method in the ViewModelBase and never even think about it again!
Never underestimate the power of human stupidity RAH
-
Basically, that's spot on. Although it also ships with IEditableCollectionView which you may want to take advantage off if you are adding to collections.
Forgive your enemies - it messes with their heads
My blog | My articles | MoXAML PowerToys | Mole 2010 - debugging made easier - my favourite utility
That is kind of disappointing. Because really - the easy solution would be this: bind data model->controls only once. Do not bind back until said so (ie - user clicks OK). Maybe this would stand in the way of other things like validation, I don't know, but still I would expect that .net framework comes a bit more prepared for this very common scenario other than provide an interface any kid could write and let programmers worry about the rest. Anyway, thanks for helping me understand this.
-
That is kind of disappointing. Because really - the easy solution would be this: bind data model->controls only once. Do not bind back until said so (ie - user clicks OK). Maybe this would stand in the way of other things like validation, I don't know, but still I would expect that .net framework comes a bit more prepared for this very common scenario other than provide an interface any kid could write and let programmers worry about the rest. Anyway, thanks for helping me understand this.
Did you download and try the sample in my blog entry? Basically I created a couple of reusable classes in there that you can just use in your project without needing to reinvent any wheels.
Forgive your enemies - it messes with their heads
My blog | My articles | MoXAML PowerToys | Mole 2010 - debugging made easier - my favourite utility
-
I got to give you 5 as this is exactly the approach I used (before I ran across IEditable). I copy the object in the selected property change and bind the editable## to the UI. Chucked the copy method in the ViewModelBase and never even think about it again!
Never underestimate the power of human stupidity RAH
-
Thank you!
Computers have been intelligent for a long time now. It just so happens that the program writers are about as effective as a room full of monkeys trying to crank out a copy of Hamlet.
I'm going to put my head on the block here and say that reflection works fine because while it's not the fastest solution, this tends not to matter to the user because this is not an operation they are going to be performing 1000s of times a second. That's why my solution uses reflection - it's easy to implement, easy to understand and conforms to the interfaces that WPF expects to see.
Forgive your enemies - it messes with their heads
My blog | My articles | MoXAML PowerToys | Mole 2010 - debugging made easier - my favourite utility