diff --git a/Nuclex.Windows.Forms (net-4.0).csproj b/Nuclex.Windows.Forms (net-4.0).csproj
index fbd742d..37b940b 100644
--- a/Nuclex.Windows.Forms (net-4.0).csproj
+++ b/Nuclex.Windows.Forms (net-4.0).csproj
@@ -57,6 +57,17 @@
+
+
+
+ MessageEventArgs.cs
+
+
+
+
+ MessageText.cs
+
+
diff --git a/Source/Messages/IMessageService.cs b/Source/Messages/IMessageService.cs
new file mode 100644
index 0000000..1ac53c1
--- /dev/null
+++ b/Source/Messages/IMessageService.cs
@@ -0,0 +1,55 @@
+#region CPL License
+/*
+Nuclex Framework
+Copyright (C) 2002-2019 Nuclex Development Labs
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the IBM Common Public License as
+published by the IBM Corporation; either version 1.0 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+IBM Common Public License for more details.
+
+You should have received a copy of the IBM Common Public
+License along with this library
+*/
+#endregion
+
+using System;
+using System.Windows.Forms;
+
+namespace Nuclex.Windows.Forms.Messages {
+
+ /// Performs simple user interaction
+ ///
+ /// Methods provided by this service can be covered using plain old message boxes
+ /// and do not require special dialogs or calls to the task dialog API.
+ ///
+ public interface IMessageService {
+
+ /// Triggered when a message is about to be displayed to the user
+ event EventHandler MessageDisplaying;
+
+ /// Triggered when the user has acknowledged the current message
+ event EventHandler MessageAcknowledged;
+
+ /// Asks the user a question that can be answered via several buttons
+ /// Image that will be shown on the message box
+ /// Text that will be shown to the user
+ /// Buttons available for the user to click on
+ /// The button the user has clicked on
+ DialogResult ShowQuestion(
+ MessageBoxIcon image, MessageText text, MessageBoxButtons buttons
+ );
+
+ /// Displays a notification to the user
+ /// Image that will be shown on the message bx
+ /// Text that will be shown to the user
+ void ShowNotification(MessageBoxIcon image, MessageText text);
+
+ }
+
+} // namespace Nuclex.Windows.Forms.Messages
diff --git a/Source/Messages/MessageEventArgs.Test.cs b/Source/Messages/MessageEventArgs.Test.cs
new file mode 100644
index 0000000..9ef7ba3
--- /dev/null
+++ b/Source/Messages/MessageEventArgs.Test.cs
@@ -0,0 +1,49 @@
+#region CPL License
+/*
+Nuclex Framework
+Copyright (C) 2002-2019 Nuclex Development Labs
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the IBM Common Public License as
+published by the IBM Corporation; either version 1.0 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+IBM Common Public License for more details.
+
+You should have received a copy of the IBM Common Public
+License along with this library
+*/
+#endregion
+
+using System;
+using System.Windows.Forms;
+
+using NUnit.Framework;
+
+namespace Nuclex.Windows.Forms.Messages {
+
+ /// Unit tests for the message box event argument container
+ [TestFixture]
+ internal class MessageEventArgsTest {
+
+ /// Verifies that the image associated with the message gets stored
+ [Test]
+ public void ImageIsStored() {
+ var arguments = new MessageEventArgs(MessageBoxIcon.Exclamation, null);
+ Assert.AreEqual(MessageBoxIcon.Exclamation, arguments.Image);
+ }
+
+ /// Verifies that the text associated with the message gets stored
+ [Test]
+ public void TextIsStored() {
+ var text = new MessageText();
+ var arguments = new MessageEventArgs(MessageBoxIcon.None, text);
+ Assert.AreSame(text, arguments.Text);
+ }
+
+ }
+
+} // namespace Nuclex.Windows.Forms.Messages
diff --git a/Source/Messages/MessageEventArgs.cs b/Source/Messages/MessageEventArgs.cs
new file mode 100644
index 0000000..0fba56e
--- /dev/null
+++ b/Source/Messages/MessageEventArgs.cs
@@ -0,0 +1,54 @@
+#region CPL License
+/*
+Nuclex Framework
+Copyright (C) 2002-2019 Nuclex Development Labs
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the IBM Common Public License as
+published by the IBM Corporation; either version 1.0 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+IBM Common Public License for more details.
+
+You should have received a copy of the IBM Common Public
+License along with this library
+*/
+#endregion
+
+using System;
+using System.Windows.Forms;
+
+namespace Nuclex.Windows.Forms.Messages {
+
+ /// Provides a displayed message and its severity to event subscribers
+ public class MessageEventArgs : EventArgs {
+
+ /// Initializes a new message box event argument container
+ /// Image the message box will be displaying
+ /// Text that will be displayed in the message box
+ public MessageEventArgs(MessageBoxIcon image, MessageText text) {
+ this.image = image;
+ this.text = text;
+ }
+
+ /// Image that indicates the severity of the message being displayed
+ public MessageBoxIcon Image {
+ get { return this.image; }
+ }
+
+ /// Text that is being displayed in the message box
+ public MessageText Text {
+ get { return this.text; }
+ }
+
+ /// Image that indicates the severity of the message being displayed
+ private MessageBoxIcon image;
+ /// Text that is being displayed in the message box
+ private MessageText text;
+
+ }
+
+} // namespace Nuclex.Windows.Forms.Messages
diff --git a/Source/Messages/MessageServiceHelper.cs b/Source/Messages/MessageServiceHelper.cs
new file mode 100644
index 0000000..526e9b9
--- /dev/null
+++ b/Source/Messages/MessageServiceHelper.cs
@@ -0,0 +1,108 @@
+#region CPL License
+/*
+Nuclex Framework
+Copyright (C) 2002-2019 Nuclex Development Labs
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the IBM Common Public License as
+published by the IBM Corporation; either version 1.0 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+IBM Common Public License for more details.
+
+You should have received a copy of the IBM Common Public
+License along with this library
+*/
+#endregion
+
+using System;
+using System.Windows.Forms;
+
+namespace Nuclex.Windows.Forms.Messages {
+
+ /// Contains helper methods for the message service
+ public static class MessageServiceHelper {
+
+ /// Asks the user a question that can be answered with yes or no
+ ///
+ /// Message service that will be used to display the question
+ ///
+ /// Text that will be shown on the message box
+ /// The button the user has clicked on
+ public static DialogResult AskYesNo(
+ this IMessageService messageService, MessageText text
+ ) {
+ return messageService.ShowQuestion(
+ MessageBoxIcon.Question, text, MessageBoxButtons.YesNo
+ );
+ }
+
+ /// Asks the user a question that can be answered with ok or cancel
+ ///
+ /// Message service that will be used to display the question
+ ///
+ /// Text that will be shown on the message box
+ /// The button the user has clicked on
+ public static DialogResult AskOkCancel(
+ this IMessageService messageService, MessageText text
+ ) {
+ return messageService.ShowQuestion(
+ MessageBoxIcon.Question, text, MessageBoxButtons.OKCancel
+ );
+ }
+
+ ///
+ /// Asks the user a question that can be answered with yes, no or cancel
+ ///
+ ///
+ /// Message service that will be used to display the question
+ ///
+ /// Text that will be shown on the message box
+ /// The button the user has clicked on
+ public static DialogResult AskYesNoCancel(
+ this IMessageService messageService, MessageText text
+ ) {
+ return messageService.ShowQuestion(
+ MessageBoxIcon.Question, text, MessageBoxButtons.YesNoCancel
+ );
+ }
+
+ /// Displays an informative message
+ ///
+ /// Message service that will be used to display the warning
+ ///
+ /// Text to be displayed on the warning message
+ public static void Inform(
+ this IMessageService messageService, MessageText text
+ ) {
+ messageService.ShowNotification(MessageBoxIcon.Information, text);
+ }
+
+ /// Displays a warning
+ ///
+ /// Message service that will be used to display the warning
+ ///
+ /// Text to be displayed on the warning message
+ public static void Warn(
+ this IMessageService messageService, MessageText text
+ ) {
+ messageService.ShowNotification(MessageBoxIcon.Warning, text);
+ }
+
+ /// Reports an error
+ ///
+ /// Message service that will be used to display the warning
+ ///
+ /// Text to be displayed on the warning message
+ public static void ReportError(
+ this IMessageService messageService, MessageText text
+ ) {
+ messageService.ShowNotification(MessageBoxIcon.Error, text);
+ }
+
+ }
+
+} // namespace Nuclex.Windows.Forms.Messages
diff --git a/Source/Messages/MessageText.Test.cs b/Source/Messages/MessageText.Test.cs
new file mode 100644
index 0000000..767b1f8
--- /dev/null
+++ b/Source/Messages/MessageText.Test.cs
@@ -0,0 +1,51 @@
+#region CPL License
+/*
+Nuclex Framework
+Copyright (C) 2002-2019 Nuclex Development Labs
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the IBM Common Public License as
+published by the IBM Corporation; either version 1.0 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+IBM Common Public License for more details.
+
+You should have received a copy of the IBM Common Public
+License along with this library
+*/
+#endregion
+
+using System;
+using System.Windows;
+
+using NUnit.Framework;
+
+namespace Nuclex.Windows.Forms.Messages {
+
+ /// Unit tests for the message text container
+ [TestFixture]
+ internal class MessageTextTest {
+
+ /// Ensures that the message text class provides a copy constructor
+ [Test]
+ public void HasCopyConstructor() {
+ var text = new MessageText() {
+ Caption = "Caption",
+ Message = "Message",
+ Details = "Details",
+ ExpandedDetails = "ExpandedDetails"
+ };
+ var copy = new MessageText(text);
+
+ Assert.AreEqual(text.Caption, copy.Caption);
+ Assert.AreEqual(text.Message, copy.Message);
+ Assert.AreEqual(text.Details, copy.Details);
+ Assert.AreEqual(text.ExpandedDetails, copy.ExpandedDetails);
+ }
+
+ }
+
+} // namespace Nuclex.Windows.Forms.Messages
diff --git a/Source/Messages/MessageText.cs b/Source/Messages/MessageText.cs
new file mode 100644
index 0000000..dea8405
--- /dev/null
+++ b/Source/Messages/MessageText.cs
@@ -0,0 +1,55 @@
+#region CPL License
+/*
+Nuclex Framework
+Copyright (C) 2002-2019 Nuclex Development Labs
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the IBM Common Public License as
+published by the IBM Corporation; either version 1.0 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+IBM Common Public License for more details.
+
+You should have received a copy of the IBM Common Public
+License along with this library
+*/
+#endregion
+
+using System;
+
+namespace Nuclex.Windows.Forms.Messages {
+
+ /// Text that will be displayed in a message box
+ public class MessageText {
+
+ /// Initializs a new message text
+ public MessageText() { }
+
+ /// Initializes a new message text by copying another instance
+ /// Instance that will be copied
+ public MessageText(MessageText other) {
+ Caption = other.Caption;
+ Message = other.Message;
+ Details = other.Details;
+ ExpandedDetails = other.ExpandedDetails;
+ }
+
+ /// The caption used when the is displayed in a message box
+ public string Caption { get; set; }
+ /// Main message being displayed to the user
+ public string Message { get; set; }
+ /// Message details shown below the main message
+ public string Details { get; set; }
+ ///
+ /// Additional informations the user can display by expanding
+ /// the message dialog. Can be null, in which case the message dialog
+ /// will not be expandable.
+ ///
+ public string ExpandedDetails { get; set; }
+
+ }
+
+} // namespace Nuclex.Windows.Forms.Messages
diff --git a/Source/Messages/StandardMessageBoxManager.cs b/Source/Messages/StandardMessageBoxManager.cs
new file mode 100644
index 0000000..b5e3b3f
--- /dev/null
+++ b/Source/Messages/StandardMessageBoxManager.cs
@@ -0,0 +1,162 @@
+#region CPL License
+/*
+Nuclex Framework
+Copyright (C) 2002-2019 Nuclex Development Labs
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the IBM Common Public License as
+published by the IBM Corporation; either version 1.0 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+IBM Common Public License for more details.
+
+You should have received a copy of the IBM Common Public
+License along with this library
+*/
+#endregion
+
+using System;
+using System.Windows.Forms;
+
+namespace Nuclex.Windows.Forms.Messages {
+
+ /// Uses task dialogs to display message boxes
+ public class StandardMessageBoxManager : IMessageService {
+
+ #region class MessageScope
+
+ /// Triggers the message displayed and acknowledged events
+ private class MessageScope : IDisposable {
+
+ ///
+ /// Initializes a new message scope, triggering the message displayed event
+ ///
+ /// Message service the scope belongs to
+ /// Image of the message being displayed
+ /// Text contained in the message being displayed
+ public MessageScope(
+ StandardMessageBoxManager self, MessageBoxIcon image, MessageText text
+ ) {
+ EventHandler messageDisplayed = self.MessageDisplaying;
+ if(messageDisplayed != null) {
+ messageDisplayed(this, new MessageEventArgs(image, text));
+ }
+
+ this.self = self;
+ }
+
+ /// Triggers the message acknowledged event
+ public void Dispose() {
+ EventHandler messageAcknowledged = self.MessageAcknowledged;
+ if(messageAcknowledged != null) {
+ messageAcknowledged(this, EventArgs.Empty);
+ }
+ }
+
+ /// Message service the scope belongs to
+ private StandardMessageBoxManager self;
+
+ }
+
+ #endregion // class MessageScope
+
+ /// Delegate for the standard message box show function
+ /// Window that will modally display the message box
+ /// Text that will be presented to the user
+ /// Contents of the message box' title bar
+ /// Buttons available for the user to choose from
+ /// Icon that will be displayed next to the text
+ /// The choice made by the user if multiple buttons were provided
+ private delegate DialogResult ShowMessageBoxDelegate(
+ IWin32Window owner,
+ string text,
+ string caption,
+ MessageBoxButtons buttons,
+ MessageBoxIcon icon
+ );
+
+ /// Triggered when a message is displayed to the user
+ public event EventHandler MessageDisplaying;
+
+ /// Triggered when the user has acknowledged the current message
+ public event EventHandler MessageAcknowledged;
+
+ /// Initializes a new task dialog message service
+ public StandardMessageBoxManager() : this(NullActiveWindowTracker.Default) { }
+
+ /// Initializes a new task dialog message service
+ ///
+ /// Active window tracker used to obtain the parent window for message boxes
+ ///
+ public StandardMessageBoxManager(IActiveWindowTracker tracker) {
+ this.tracker = tracker;
+ this.showMessageDelegate = new ShowMessageBoxDelegate(MessageBox.Show);
+ }
+
+ /// Asks the user a question that can be answered via several buttons
+ /// Image that will be shown on the message box
+ /// Text that will be shown to the user
+ /// Buttons available for the user to click on
+ /// The button the user has clicked on
+ public DialogResult ShowQuestion(
+ MessageBoxIcon image, MessageText text, MessageBoxButtons buttons
+ ) {
+ using(var scope = new MessageScope(this, image, text)) {
+ return showMessageBoxInActiveUiThread(
+ text.Message,
+ text.Caption,
+ buttons,
+ image
+ );
+ }
+ }
+
+ /// Displays a notification to the user
+ /// Image that will be shown on the message bx
+ /// Text that will be shown to the user
+ public void ShowNotification(MessageBoxIcon image, MessageText text) {
+ using(var scope = new MessageScope(this, image, text)) {
+ showMessageBoxInActiveUiThread(
+ text.Message,
+ text.Caption,
+ MessageBoxButtons.OK,
+ image
+ );
+ }
+ }
+
+ /// Displays the message box in the active view's thread
+ /// Text that will be presented to the user
+ /// Contents of the message box' title bar
+ /// Buttons available for the user to choose from
+ /// Image that will be displayed next to the text
+ ///
+ private DialogResult showMessageBoxInActiveUiThread(
+ string message,
+ string caption,
+ MessageBoxButtons buttons,
+ MessageBoxIcon image
+ ) {
+ Form mainWindow = this.tracker.ActiveWindow;
+ if(mainWindow != null) {
+ return (DialogResult)mainWindow.Invoke(
+ this.showMessageDelegate,
+ (IWin32Window)mainWindow, message, caption, buttons, image
+ );
+ }
+
+ // No window tracker or unknown main window -- just show the message box
+ return MessageBox.Show(message, caption, buttons, image);
+ }
+
+ /// Provides the currently active top-level window
+ private IActiveWindowTracker tracker;
+ /// Delegate for the MessageBox.Show() method
+ private ShowMessageBoxDelegate showMessageDelegate;
+
+ }
+
+} // namespace Nuclex.Windows.Forms.Messages
diff --git a/Source/WindowManager.Test.cs b/Source/WindowManager.Test.cs
index 1f44fcf..dd5bd48 100644
--- a/Source/WindowManager.Test.cs
+++ b/Source/WindowManager.Test.cs
@@ -1,4 +1,24 @@
-using System;
+#region CPL License
+/*
+Nuclex Framework
+Copyright (C) 2002-2019 Nuclex Development Labs
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the IBM Common Public License as
+published by the IBM Corporation; either version 1.0 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+IBM Common Public License for more details.
+
+You should have received a copy of the IBM Common Public
+License along with this library
+*/
+#endregion
+
+using System;
using NUnit.Framework;