In diesem Beispiel möchte ich über meine Erfahrungen zum über das Schliessen eines Formulars per Programmcode berichten.
Vor kurzem habe ich ein Beispiel zum Überprüfen und Absichern von Geschäftsregeln in einem Outlook Add-in berichtet:
http://www.outlooksharp.de/Home/tabid/36/EntryId/54/Geschaftsregeln-fur-Outlook-Formulare.aspx
Das Problem:
Implementiert man eine Lösung zum Sicherstellen von Geschäftsregeln möchte man den Benutzer darauf hinweisen, dass irgendetwas nicht korrekt ausgefüllt ist. Dazu kann man dem Benutzer einen modalen Dialog(MessageBox) anzeigen. Ist eine der Regeln ungültig, kann der Benutzer weder speichern – noch das Formular schliessen. Man sollte dem Benutzer aber immer die Möglichkeit geben einen Vorgang abzubrechen. Zu diesem Zweck kann man dem Benutzer im der Close-Benachrichtigung einen Dialog mit zwei Schaltflächen anzeigen z.B. Ok und Abbrechen. Klickt der benutzer in diesem Fall auf Abbrechen – soll das Formular einfach geschlossen werden ohne die modifizierten Daten zu speichern.
Prinzipiell sieht die Lösung wie folgt aus:
///<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;
}
Wenn eine der geschäftsregeln nicht eingehalten wird, liefert die Validate-Methode false zurück.
Klickt der Benutzer auf die Abbrechen-Schaltfläche im angezeigten Dialog, soll das Formular ohne die Daten zu speichern geschlossen werden.
Um das zu erreichen wird ein Flag_closeAfterCancel auf true gesetzt. Normalerweise könnte man jetzt einfach die Methode Inspector.Close(Outlook.OlInspectorClose.OlDiscard) im Item_Close event aufrufen.
///<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);
}
}
}
Leider musste ich feststellen, dass dies so nicht funktioniert. Anstatt das Formular zu schliessen, wird ein "Möchten Sie die Änderungen Speichern"-Dialog angezeigt.
Außerdem wurden im Outlook Objekt Model(OOM) einige Änderungen durchgeführt, welche eine korrekte Funktion verschiedener Methoden im Close-Event verhindern, siehe KB929593.
Als Lösungsansatz kann man einen Timer starten und im Timer_Tick event die Methode Inspector.Close aufrufen.
So sieht der modifizierte Programmcode dazu aus:
///<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);
}
Jedoch wenn man dies ausführt kommt folgendes Resultat:
- Es wird kein "Möchten Sie die Änderungen Speichern"-Dialog angezeigt
- Das Formular wird geschlossen
- Die Daten werden gespeichert
Es funktioniert einfach nicht wie gewünscht.
Nach meinen Erkenntnissen ist die einzig funktionierene Form anstatt der Inspector.Close(olDiscard)- die Item.Close(olDiscard)-Mehtode aufzurufen.
Der korrekte Code sieht dementsprechend aus:
void _closeTimer_Tick(object sender, EventArgs e) {
_closeTimer.Stop();
_closeTimer.Dispose();
// Close the current Form without saving
Item.Close(Outlook.OlInspectorClose.olDiscard);
}
Nur mit dieser Implementierung wird das Formular geschlossen ohne die Daten zu speichern.
Herzlichen Dank an Ken Slovak, durch Ihn bin ich auf die korrekte Lösung gekommen.
Viele Grüße – Helmut Obertanner
http://www.x4u.de