In this post I will share some tips about closing an Inspector without saving changed data programmatically.
Recently I blogged about enforcing BusinessRules within Outlook here:
http://www.outlooksharp.de/Home/tabid/36/EntryId/53/Enforcing-business-rules-for-Outlook-Items.aspx
The problem:
If you use BusinessRules in your AddIn and validate the rules at the Item_Write and the Item_Close event you may cancel the current operation and display the user a MessageBox that something went wrong. If the rule isn't successfully validated, the user can't close this form. So you need to give the user the opportunity to close the Form without saving the modified values(discard changes). For this case we can display a MessageBox with two buttons (OK/Cancel) to the user. When the user clicks on Cancel, we just want to close the Form without saving the data.
To archive this, you can use the following code snippet:
///<summary>
/// Flag is used to close the Form when Cancel is clicked
///</summary>
bool _closeAfterCancel = false;
///<summary>
/// Validates the BusinessRules and returns true if all rules are valid
///</summary>
///<param name="showCancelButton">If true, a OK/Cancel MessageBox is displayed to the user</param>
///<returns>true when all rules are valid</returns>
publicbool Validate(bool showCancelButton) {
if (Item.Saved) returntrue;
// Default value
_closeAfterCancel = false;
// if every business rule is valid we return true
if (_BusinessRules.TrueForAll(X4UBusinessRule.IsRuleValid)) returntrue;
// no ?
// show a warning to the user and
StringBuilder message = newStringBuilder(500);
message.AppendLine("You can't save this Item, because the following requirements are not met:");
foreach (X4UBusinessRule rule in _BusinessRules) {
if (!rule.IsValid()) message.AppendLine(rule.Description);
}
// display a message to the user what's wrong.
DialogResult messageBoxResult = MessageBox.Show (newOutlookWin32Window(Inspector),
message.ToString(), // Message
"Warning!", // Caption
showCancelButton ? MessageBoxButtons.OKCancel :MessageBoxButtons.OK, // Which Buttons should we display
MessageBoxIcon.Exclamation, // The Icon
MessageBoxDefaultButton.Button1 // The Default Button
);
// when OK-Button is clicked, we cancel the Operation
if (showCancelButton && messageBoxResult==DialogResult.Cancel ){
_closeAfterCancel = true;
}
returnfalse;
}
So, if rules are failing the Validate-Method returns false.
If the user clicks on Cancel in the MessageBox, the Form should be closed without saving the data.
To archive this a flag _closeAfterCancel is set to true. Basically you will just call Inspector.Close(Outlook.OlInspectorClose.OlDiscard) in the Item_Close event.
///<summary>
/// This Method is called when the Item is going to be closed
///</summary>
///<param name="Cancel"></param>
void Item_Close(refbool Cancel) {
if (!_closeAfterCancel) {
Cancel = !Validate(true); // MessageBox with OK + Cancel Button
if (_closeAfterCancel) {
Inspector.Close(Outlook.OlInspectorClose.olDiscard);
}
}
}
I found out that this just won't work. Instead the AskForSave Dialog is displayed to the user.
Also there where some changes in the Outlook Object Model that prvents that methods working correctly in the Item_Close event, see KB929593.
So I tried to get it working using a timer, and call Inspector.Close in the Timer_Tick event.
See the modified code:
///<summary>
/// Used to call Close() out of the Item_Close event.
///</summary>
Timer _closeTimer;
///<summary>
/// This Method is called when the Item is going to be closed
///</summary>
///<param name="Cancel"></param>
void Item_Close(refbool Cancel) {
if (!_closeAfterCancel) {
Cancel = !Validate(true); // MessageBox with OK + Cancel Button
if (_closeAfterCancel) {
_closeTimer = newTimer();
_closeTimer.Tick += newEventHandler(_closeTimer_Tick);
_closeTimer.Start();
}
}
}
void _closeTimer_Tick(object sender, EventArgs e) {
_closeTimer.Stop();
_closeTimer.Dispose();
// Close the current Form without saving
Inspector.Close(Outlook.OlInspectorClose.olDiscard);
}
When running this code:
- no AskForSave dialog is shown
- the Form is closed
- the data is saved
It just won't work.
The only way to get it working is to call the Item.Close method instead.
So – the correct method would look like this:
void _closeTimer_Tick(object sender, EventArgs e) {
_closeTimer.Stop();
_closeTimer.Dispose();
// Close the current Form without saving
Item.Close(Outlook.OlInspectorClose.olDiscard);
}
Only this way you can correctly close the current Form without saving the data.
My special thanks to Ken Slovak who pointed me to the correct solution.
Greets – Helmut Obertanner
http://www.x4u.de