WPF: Save on window close

WPF: Save on window close

Old forum URL: forums.lhotka.net/forums/t/5591.aspx


ajj3085 posted on Tuesday, October 14, 2008

Hi,

I'm trying to build up my Wpf library of general helper classes to give a consistent user experience.

I'm creating a user control which contains everything needed to edit a business object.  I'm also creating a BusinessEditWindow, which is a subclass of Wpf's Window.

I'm trying to override the OnClosing method.  The goal is to prompt the user if the window is closing at the BO is dirty.  If the BO isn't valid, the choice is close the window and lose changes, or cancel closing of the window.

If the object is valid though, there are three choices.  Saving the BO and closing the window, discarding the BO and closing the window, or canceling the window close.

The problem is with the save; if there's an error, I want to throw up my error dialog, and cancel the window closing.  I'm hitting a problem though, and I'm not sure how to solve it.

My initial idea was to have every control implement a SaveBusinessObject method, which returns true or false; true means the BO saved, false means there was some kind of exception.  Not sure how to code that, since the CslaDataProvider is handling the save command for me.

My next choice was to allow an exception to be thrown.. except the DataProvider's model is to check the Error property of the DP I'm guessing in an event handler for DataChanged.  the problem there is throwing and catching the exception doesn't allow the CslaDataProvider to reset the BO to the instance prior to calling save.

So, I'm not sure how I should continue here.  I also have concerns because the DataProvider is asyncronous, so that my UI stays nice and snappy and windows open immediately.

Thanks
Andy

sergeyb replied on Tuesday, October 14, 2008

Here are a few thoughts

1.       You can have your inherited controls expose data provider instead having BOSave.  You can probably even skip that if you follow a naming convention for provider name, although this seems dirty to me.

2.       At that point you can

a.       Check for changes

b.      Set provider to be synchronous, as I do not think asynchronous mode will work here.

c.       Add event handler for data changed

d.      Fire Save() on provider

e.      Data Changed I think will fire two times (to force UI refresh)

f.        If error is not null in first Data Changed handler, you know you have the error.

g.       After second Data Changed you can remove handler.

h.      Reset provider back to original state (synch or async)

i.         Check for error

j.        If there was one, popup the message, set cancel to true.

k.       Else close the form

 

Sergey Barskiy

Principal Consultant

office: 678.405.0687 | mobile: 404.388.1899

Magenic ®

Microsoft Worldwide Partner of the Year | Custom Development Solutions, Technical Innovation

 

From: ajj3085 [mailto:cslanet@lhotka.net]
Sent: Tuesday, October 14, 2008 3:41 PM
To: Sergey Barskiy
Subject: [CSLA .NET] WPF: Save on window close

 

Hi,

I'm trying to build up my Wpf library of general helper classes to give a consistent user experience.

I'm creating a user control which contains everything needed to edit a business object.  I'm also creating a BusinessEditWindow, which is a subclass of Wpf's Window.

I'm trying to override the OnClosing method.  The goal is to prompt the user if the window is closing at the BO is dirty.  If the BO isn't valid, the choice is close the window and lose changes, or cancel closing of the window.

If the object is valid though, there are three choices.  Saving the BO and closing the window, discarding the BO and closing the window, or canceling the window close.

The problem is with the save; if there's an error, I want to throw up my error dialog, and cancel the window closing.  I'm hitting a problem though, and I'm not sure how to solve it.

My initial idea was to have every control implement a SaveBusinessObject method, which returns true or false; true means the BO saved, false means there was some kind of exception.  Not sure how to code that, since the CslaDataProvider is handling the save command for me.

My next choice was to allow an exception to be thrown.. except the DataProvider's model is to check the Error property of the DP I'm guessing in an event handler for DataChanged.  the problem there is throwing and catching the exception doesn't allow the CslaDataProvider to reset the BO to the instance prior to calling save.

So, I'm not sure how I should continue here.  I also have concerns because the DataProvider is asyncronous, so that my UI stays nice and snappy and windows open immediately.

Thanks
Andy


SS012010 replied on Tuesday, January 12, 2010

Hi,
I'm new to CSLA.
I want my web app. to prompt the user to save his unsaved data befor he navigates away from the page. It has master page with treeview which is used to navigate through the app. On lot of pages i'm using formview bound to BO.

Thanks,
SS

RockfordLhotka replied on Wednesday, January 13, 2010

To do this in a web app you'll need to use some client-side script to prevent the user from navigating away - that's a pretty common web thing, and I'm sure you can find examples of the script by googling with Bing :)

SS012010 replied on Wednesday, January 13, 2010

Hi Rocky,
Thanks alot for your quick response.
Actually I was trying to find if there is a way in which i can leverage the the IsDirty property of the BO.

RockfordLhotka replied on Wednesday, January 13, 2010

This is the web, not Windows :)

Remember that the user is just interacting with a relatively smart terminal (the browser) that is disconnected from your server 99.999% of the time. When they try to navigate to another page, the browser is not connected to your server, and is under no obligation to ask your server for permission - that's just not part of the web model.

You may be able to write some AJAX client script that does talk to the server to get permission. I'm not sure that's possible. The only thing I've seen is that browsers have a hook you can use to cause the browser to pop up a simple yes/no dialog to tell the user they are navigating away and will lose data - the user can still click "yes, I want to leave" and you can't stop them from going.

ajj3085 replied on Wednesday, January 13, 2010

I've done this, having a page level javascript variable called isDirty.  I declare it like this:

var isDirty = [asp:Literal Id="IsDirtyLit" runat="server"/];

And set it on each page load to reflect the state of the BO. 

That's not all you have to do though; you also need to listen (in javascript) to things like keypress, clicked, etc, and set that flag to true.  Basically once the user changes the state of controls on the page, your object should be considered dirty as well.

It seems to work fairly well, but you can't rely soley on the Csla IsDirty property because the BO itself won't be dirty until a page submit.

And all you'll be able to do is maybe provide a "Lose changes?" prompt.

Copyright (c) Marimer LLC