Best way for 'OK' and 'Cancel' button implementation in a modal dialog
-
I have been working on a WPF application and looking for the best way to implement the 'Ok' and 'Cancel' button click functionality in the modal dialog boxes. The question has two parts: Part -1: Currently, I am doing it by creating a copy/clone of the actual object whenever we load the dialog. Later, I perform all the operations on the cloned object in the Modal dialog. If user press 'Ok', i'll assign all the values in the clone object to the actual object. If user press 'Cancel, i'll discard the cloned object and set it to null. For E.g: Suppose, I have a class Person
Class Person
{
public string FirstName {get; set;}
public string LastName {get; set;}
}I have another class which holds the list of 'Person' Class PersonContainer { public List Persons{get; set;} } We have a Window class 'PersonViewModel' which has all the things with respect to the view. This class has a ObservableCollection which is bound to a Datagrid in my View and properties 'FirstName and LastName' are bound to the columns of the Datagrid. The view contains button to 'Add/Remove/Modify' the records and 'Ok' and 'Cancel' button. suppose we have PersonContainer object 'originalContainer' with 2 records. In the load event of the view, we create a copy/clone of PersonContainer with 2 records. Let's call it as clonedContainer. When we perform any operation(Add/Remove/Modify) through the dialog, we do it on clonedContainer. Once, we are done, on press of 'Ok' button, we just update originalContainer with the clonedContainer. On press of 'Cancel', we discard the 'clonedContainer' and set it to null. Q: what could be the best way to handle 'Ok' and 'Cancel' in a dialog? Is creating a cloned object right way? Part 2: I have to implement the undo/redo of all the actions(Add/Remove/Modify the record) that happened on the Dialog. This has been implemented through the ICommand pattern with Execute/Unexecute methods. Whenever, we add a record, we add it the through the Execute method. However, we use the clonedContainer object and not the real one. In the Unexecute, I am using the 'originalContainer' instance and remove the added Person object. Now, if we perform 'Redo', we need to create the removed 'Person' object. By this time, clonedContainer is no more as it has been destroyed once we close the dialog. Q: How can we implement undo/redo here? Thanks in advance!!! Rags
-
I have been working on a WPF application and looking for the best way to implement the 'Ok' and 'Cancel' button click functionality in the modal dialog boxes. The question has two parts: Part -1: Currently, I am doing it by creating a copy/clone of the actual object whenever we load the dialog. Later, I perform all the operations on the cloned object in the Modal dialog. If user press 'Ok', i'll assign all the values in the clone object to the actual object. If user press 'Cancel, i'll discard the cloned object and set it to null. For E.g: Suppose, I have a class Person
Class Person
{
public string FirstName {get; set;}
public string LastName {get; set;}
}I have another class which holds the list of 'Person' Class PersonContainer { public List Persons{get; set;} } We have a Window class 'PersonViewModel' which has all the things with respect to the view. This class has a ObservableCollection which is bound to a Datagrid in my View and properties 'FirstName and LastName' are bound to the columns of the Datagrid. The view contains button to 'Add/Remove/Modify' the records and 'Ok' and 'Cancel' button. suppose we have PersonContainer object 'originalContainer' with 2 records. In the load event of the view, we create a copy/clone of PersonContainer with 2 records. Let's call it as clonedContainer. When we perform any operation(Add/Remove/Modify) through the dialog, we do it on clonedContainer. Once, we are done, on press of 'Ok' button, we just update originalContainer with the clonedContainer. On press of 'Cancel', we discard the 'clonedContainer' and set it to null. Q: what could be the best way to handle 'Ok' and 'Cancel' in a dialog? Is creating a cloned object right way? Part 2: I have to implement the undo/redo of all the actions(Add/Remove/Modify the record) that happened on the Dialog. This has been implemented through the ICommand pattern with Execute/Unexecute methods. Whenever, we add a record, we add it the through the Execute method. However, we use the clonedContainer object and not the real one. In the Unexecute, I am using the 'originalContainer' instance and remove the added Person object. Now, if we perform 'Redo', we need to create the removed 'Person' object. By this time, clonedContainer is no more as it has been destroyed once we close the dialog. Q: How can we implement undo/redo here? Thanks in advance!!! Rags
I don't know why you cloned the object, if the collection keeps the current record, you can save the index of it and if cancel is clicked, remove from the collection and only save when the save button is click, here is a small sample, just play with this and see if it can help you. 1-You need to implement commanding in your project (you are already doing it) 2-in your view link you button to a command in your viewmodel Example a Save button: 4-remember your imports, this way you can display on the view the message for the user to answer and don't need to clone.
-
I have been working on a WPF application and looking for the best way to implement the 'Ok' and 'Cancel' button click functionality in the modal dialog boxes. The question has two parts: Part -1: Currently, I am doing it by creating a copy/clone of the actual object whenever we load the dialog. Later, I perform all the operations on the cloned object in the Modal dialog. If user press 'Ok', i'll assign all the values in the clone object to the actual object. If user press 'Cancel, i'll discard the cloned object and set it to null. For E.g: Suppose, I have a class Person
Class Person
{
public string FirstName {get; set;}
public string LastName {get; set;}
}I have another class which holds the list of 'Person' Class PersonContainer { public List Persons{get; set;} } We have a Window class 'PersonViewModel' which has all the things with respect to the view. This class has a ObservableCollection which is bound to a Datagrid in my View and properties 'FirstName and LastName' are bound to the columns of the Datagrid. The view contains button to 'Add/Remove/Modify' the records and 'Ok' and 'Cancel' button. suppose we have PersonContainer object 'originalContainer' with 2 records. In the load event of the view, we create a copy/clone of PersonContainer with 2 records. Let's call it as clonedContainer. When we perform any operation(Add/Remove/Modify) through the dialog, we do it on clonedContainer. Once, we are done, on press of 'Ok' button, we just update originalContainer with the clonedContainer. On press of 'Cancel', we discard the 'clonedContainer' and set it to null. Q: what could be the best way to handle 'Ok' and 'Cancel' in a dialog? Is creating a cloned object right way? Part 2: I have to implement the undo/redo of all the actions(Add/Remove/Modify the record) that happened on the Dialog. This has been implemented through the ICommand pattern with Execute/Unexecute methods. Whenever, we add a record, we add it the through the Execute method. However, we use the clonedContainer object and not the real one. In the Unexecute, I am using the 'originalContainer' instance and remove the added Person object. Now, if we perform 'Redo', we need to create the removed 'Person' object. By this time, clonedContainer is no more as it has been destroyed once we close the dialog. Q: How can we implement undo/redo here? Thanks in advance!!! Rags
Rags1512 wrote:
Q: what could be the best way to handle 'Ok' and 'Cancel' in a dialog? Is creating a cloned object right way?
There is no "right" way, there are only efficient, inefficient and non-compiling implementations. FWIW, I'm doing something similar; I clone the object and throw it in a PropertyEditor. Has a third button that says "reset" that simply clones the original again and uploads it anew in the PropertyEditor. Works well, doesn't have much overhead.
Rags1512 wrote:
Q: How can we implement undo/redo here?
An undo/redo is usually limited to the form where one is editing. You'd need the Memento-pattern, saving the internal state of the object every time the user performs an action. Undoing the action is then as simple as fetching the internal state from that point.
Bastard Programmer from Hell :suss: if you can't read my code, try converting it here[^]
-
I don't know why you cloned the object, if the collection keeps the current record, you can save the index of it and if cancel is clicked, remove from the collection and only save when the save button is click, here is a small sample, just play with this and see if it can help you. 1-You need to implement commanding in your project (you are already doing it) 2-in your view link you button to a command in your viewmodel Example a Save button: 4-remember your imports, this way you can display on the view the message for the user to answer and don't need to clone.
Thanks for the response! Here I have used Person, PersonContainer and PersonViewModel just for representation. In actual scenario, the object is complex which updates many of its properties on Addition/modification of items in the datagrid. So, saving the index won't serve the purpose as we need the actual values. Can you elaborate more on the 'imports' mentioned on #4? Still, i believe we need to clone the actual object and work on it. Appreciate, if you can help me a little detailed code. - Rags
-
Rags1512 wrote:
Q: what could be the best way to handle 'Ok' and 'Cancel' in a dialog? Is creating a cloned object right way?
There is no "right" way, there are only efficient, inefficient and non-compiling implementations. FWIW, I'm doing something similar; I clone the object and throw it in a PropertyEditor. Has a third button that says "reset" that simply clones the original again and uploads it anew in the PropertyEditor. Works well, doesn't have much overhead.
Rags1512 wrote:
Q: How can we implement undo/redo here?
An undo/redo is usually limited to the form where one is editing. You'd need the Memento-pattern, saving the internal state of the object every time the user performs an action. Undoing the action is then as simple as fetching the internal state from that point.
Bastard Programmer from Hell :suss: if you can't read my code, try converting it here[^]
Thanks for the response! Looks like memento pattern is the solution. Let me understand and try it.
-
Thanks for the response! Looks like memento pattern is the solution. Let me understand and try it.
Like Eddy said, there is no right or wrong to do it, using observable collections, you could have 2 and a flag, if the record is dirty (meaning that was modify) then in the save event in your viewmodel you just save the record, if cancel was hit and it was dirty then restore from either the db. again (re-read the record) or copy it from the other collection. What I mean with the 'imports' is that the 'Message' needs a import on the viewmodel.
-
I have been working on a WPF application and looking for the best way to implement the 'Ok' and 'Cancel' button click functionality in the modal dialog boxes. The question has two parts: Part -1: Currently, I am doing it by creating a copy/clone of the actual object whenever we load the dialog. Later, I perform all the operations on the cloned object in the Modal dialog. If user press 'Ok', i'll assign all the values in the clone object to the actual object. If user press 'Cancel, i'll discard the cloned object and set it to null. For E.g: Suppose, I have a class Person
Class Person
{
public string FirstName {get; set;}
public string LastName {get; set;}
}I have another class which holds the list of 'Person' Class PersonContainer { public List Persons{get; set;} } We have a Window class 'PersonViewModel' which has all the things with respect to the view. This class has a ObservableCollection which is bound to a Datagrid in my View and properties 'FirstName and LastName' are bound to the columns of the Datagrid. The view contains button to 'Add/Remove/Modify' the records and 'Ok' and 'Cancel' button. suppose we have PersonContainer object 'originalContainer' with 2 records. In the load event of the view, we create a copy/clone of PersonContainer with 2 records. Let's call it as clonedContainer. When we perform any operation(Add/Remove/Modify) through the dialog, we do it on clonedContainer. Once, we are done, on press of 'Ok' button, we just update originalContainer with the clonedContainer. On press of 'Cancel', we discard the 'clonedContainer' and set it to null. Q: what could be the best way to handle 'Ok' and 'Cancel' in a dialog? Is creating a cloned object right way? Part 2: I have to implement the undo/redo of all the actions(Add/Remove/Modify the record) that happened on the Dialog. This has been implemented through the ICommand pattern with Execute/Unexecute methods. Whenever, we add a record, we add it the through the Execute method. However, we use the clonedContainer object and not the real one. In the Unexecute, I am using the 'originalContainer' instance and remove the added Person object. Now, if we perform 'Redo', we need to create the removed 'Person' object. By this time, clonedContainer is no more as it has been destroyed once we close the dialog. Q: How can we implement undo/redo here? Thanks in advance!!! Rags
There are essentially two ways to do this. The first is what you've done: copy the object, have the dialog operate on that copy, and update the original if you press OK. The second is rather similar, but instead of having a copy of the base data object to operate on, you operate on a specific data object for the form (i.e. it has properties for the fields that are editable on this form only), and if you press OK you assign all the properties from that data object into the source. In the second case the data object can actually be the form itself, particularly with WPF's data binding that allows you to have UI controls display numbers, enum choices etc simply. This is normally what I do. Re undo/redo, you need to save a command when you change the original object, i.e. press OK. Do you need to be able to undo each thing individually? ... I would normally expect 'Edit Object' to end up as a single undo action which is easier (you just have a command which stores the properties that were changed and the previous value, or even the whole before and after states, of the source object). If you do need undo entries for every dialog interaction then you need to have a local command stack within the dialog, and when you save the object you can execute them all in order on the source object and push them onto the global undo stack against that object.
-
There are essentially two ways to do this. The first is what you've done: copy the object, have the dialog operate on that copy, and update the original if you press OK. The second is rather similar, but instead of having a copy of the base data object to operate on, you operate on a specific data object for the form (i.e. it has properties for the fields that are editable on this form only), and if you press OK you assign all the properties from that data object into the source. In the second case the data object can actually be the form itself, particularly with WPF's data binding that allows you to have UI controls display numbers, enum choices etc simply. This is normally what I do. Re undo/redo, you need to save a command when you change the original object, i.e. press OK. Do you need to be able to undo each thing individually? ... I would normally expect 'Edit Object' to end up as a single undo action which is easier (you just have a command which stores the properties that were changed and the previous value, or even the whole before and after states, of the source object). If you do need undo entries for every dialog interaction then you need to have a local command stack within the dialog, and when you save the object you can execute them all in order on the source object and push them onto the global undo stack against that object.
Thanks a lot.