Содержание
- How to open a message box (WPF .NET)
- Display a message box
- Handle a message box response
- Окно сообщения об ошибке для WinForms и WPF приложений
- UI error display window with task async in WPF
- 2 Answers 2
- Открытие окна сообщения (WPF .NET)
- Отображение окна сообщения
- Обработка ответа в окне сообщения
- How to show an unhandled exception window in WPF
- The WindowExceptionHandler class
- Creating the exception window
- Handle exception or exit application?
- A sample project
- Summary
How to open a message box (WPF .NET)
A message box is a dialog box that is used to quickly display information and optionally allow users to make decisions. Access to the message box is provided by the MessageBox class. A message box is displayed modally. And the code that displays the message box is paused until the user closes the message box either with the close button or a response button.
The following illustration demonstrates the parts of a message box:
- A title bar with a caption (1).
- A close button (2).
- Icon (3).
- Message displayed to the user (4).
- Response buttons (5).
For presenting or gathering complex data, a dialog box might be more suitable than a message box. For more information, see Dialog boxes overview.
Display a message box
To create a message box, you use the MessageBox class. The MessageBox.Show method lets you configure the message box text, title, icon, and buttons, shown in the following code:
The MessageBox.Show method overloads provide ways to configure the message box. These options include:
- Title bar caption
- Message icon
- Message text
- Response buttons
Here are some more examples of using a message box.
Display an alert.
The previous code displays a message box like the following image:
It’s a good idea to use the options provided by the message box class. Using the same alert as before, set more options to make it more visually appealing:
The previous code displays a message box like the following image:
Display a warning.
The previous code displays a message box like the following image:
Ask the user a question.
The previous code displays a message box like the following image:
Handle a message box response
The MessageBox.Show method displays the message box and returns a result. The result indicates how the user closed the message box:
When a user presses the buttons at the bottom of the message box, the corresponding MessageBoxResult is returned. However, if the user presses the ESC key or presses the Close button (#2 in the message box illustration), the result of the message box varies based on the button options:
Button options | ESC or Close button result |
---|---|
Ok | Ok |
OkCancel | Cancel |
YesNo | ESC keyboard shortcut and Close button disabled. User must press Yes or No. |
YesNoCancel | Cancel |
For more information on using message boxes, see MessageBox and the MessageBox sample.
Источник
Окно сообщения об ошибке для WinForms и WPF приложений
Приветствую!
В статье посвященной моему профайлеру для Entity Framework-a, я вкратце описал примененную мной форму для сообщения пользователю об исключительной ошибке в приложении. После оценки количества скачиваний примера кода, было решено выделить этот пример в отдельный проект, а также добавить поддержку WPF приложений.
Исходники библиотеки вместе с примерами опубликованы на CodePlex под свободной лицензией MIT: https://uiexceptionhandler.codeplex.com/
Подробности под катом.
Введение
Всем известно, что приложения периодически падают по самым разным причинам, при этом, крайне желательно показывать пользователю дружественное сообщение об ошибке в приложении, вместо стандартного сообщения Windows.
Что получилось
При подключенной библиотеке, в случае падения приложения будет показано следующие сообщение с просьбой добавить описание шагов которые привели к ошибке и свой email для ответа, при этом текст ошибки сохраняется в лог файл.
При клике по кнопке «Error detail information» выводиться дополнительная информация об ошибке:
Кнопка Debug позволяет подключить отладчик Visual Studio.
Кнопка «Send to Developer» отправляет письмо на почту разработчику. В случае ошибки отправки сообщения, пользователю будет предложено самому отправить лог файл разработчику на почту.
Отправленное разработчику сообщение придет в таком виде:
Использование
1. Забрать последнюю версию кода https://uiexceptionhandler.codeplex.com/SourceControl/latest
2. Собрать в Release mode.
3. Из папки «UIExceptionHandlerLibsDeploy» подключить в проект библиотеку UIExceptionHandlerWinForms.dll в случае WinForms приложения и UIExceptionHandlerWPF.dll в случае WPF приложения.
4. Инициализировать путем вызова статического метода с рядом параметров:
Как это работает
Статический метод UIException.Start подписывает метод HandleError на событие AppDomain.CurrentDomain.UnhandledException:
В качестве библиотеки для логгирования используется NLog. Для того чтобы избежать появления лишних xml файлов, вся конфигурация Nlog-а делается в коде:
Чтобы добиться максимальной простой интеграции в проект, я решил все используемые сборки объединить в одну библиотеку. Делается это при помощи приложения ILMerge, путем добавления скрипта в post-build событие:
Послесловие
Данное решение было написано для достаточно крупного проекта, применяется уже более 2-х лет, значительно улучшив процесс исправления ошибок, поскольку о каждом падении приложения узнаешь моментально, без дополнительной нотификации от пользователя.
Надеюсь это все будет кому-то полезно!
Всем спасибо за внимание!
Источник
UI error display window with task async in WPF
I am new to async and was wondering if any improvement can be made to the solution I put together from scattered information on the web.
The following (working) code shows how a button press runs logic and if there are any errors they will appear in the returned task.Exception.Handle variable which I can check in my ContinueWith code. If it’s not null, I open the error dialog window for the user. By passing in FromCurrentSynchronizationContext , I get to open the window on the UI thread and avoid issues with UI thread access.
Any improvements to make it more readable or suggest a different patter for this would be much welcomed.
2 Answers 2
This is a good fit for async await:
Regarding async await As you can see using async and await removes quite a bit of noise from the code. In general async void is smelly and should only be used for eventhavndlers. In your case it feels like a decent fit since you handle the exceptions. Async void means it cannot be awaited.
Regarding command: While I agree that this looks like a fit for a RelayCommand it is not trivial due to the async.
Here is a good read on commands for async scenarios.
Most RelayCommand implementations handle raising CanExecuteChanged poorly by calling CommandManager.InvalidateRequerySuggested which is very inefficient.
Here is a nice implementation.
Regarding scheduling Always be explicit with .ConfigureAwait(true|false) when awaiting. The default is true which means that the code continues on the synchronizationcontext it came from. This is a strange default in my opinion and ConfigureAwait is a poorly named method. In your case I think the logger and windowManager should be thread agnostic enabling .ConfigureAwait(false) Suggested implementation:
The upside with implementing it like this is that the caller will not need to remember to call it on the UI thread. It is the job of the windowmanager to schedule if needed. Hence fixing many potential bugs in one place.
Regarding the pattern Using a flag like this is fine and will work well if you refactor to relaycommand. A try-finally block makes it clear in my opinion.
Источник
Открытие окна сообщения (WPF .NET)
Окно сообщения — это диалоговое окно, которое используется для быстрого отображения информации. Дополнительно оно позволяет пользователям принимать решения. Доступ к окну сообщения предоставляется классом MessageBox. Окно сообщения отображается в модальном режиме. А выполнение кода, отображающего окно сообщения, приостанавливается, пока пользователь не закроет окно сообщения с помощью кнопки закрытия или кнопки ответа.
На следующем рисунке демонстрируются части окна сообщения:
- Заголовок окна с подписью (1).
- Кнопка «Закрыть» (2).
- Значок (3).
- Сообщение, отображаемое пользователю (4).
- Кнопки ответа (5).
Для представления или сбора сложных данных диалоговое окно может подходить больше, чем окно сообщения. Дополнительные сведения см. в разделе Общие сведения о диалоговых окнах.
Отображение окна сообщения
Чтобы создать окно сообщения, используйте класс MessageBox. Метод MessageBox.Show позволяет настроить текст, заголовок, значок и кнопки окна сообщения, как показано в следующем коде:
Перегрузки метода MessageBox.Show предоставляют способы настройки окна сообщения. Вот какие параметры доступны:
- Заголовок окна
- Значок сообщения
- Текст сообщения
- Кнопки ответа
Ниже приведено еще несколько примеров использования окна сообщения.
Предыдущий код отображает окно сообщения, как показано на следующем рисунке:
Рекомендуется использовать параметры, предоставляемые классом окна сообщения. Используя то же оповещение, что и раньше, задайте дополнительные параметры, чтобы сделать его визуально более привлекательным:
Предыдущий код отображает окно сообщения, как показано на следующем рисунке:
Предыдущий код отображает окно сообщения, как показано на следующем рисунке:
Задает вопрос пользователю.
Предыдущий код отображает окно сообщения, как показано на следующем рисунке:
Обработка ответа в окне сообщения
Метод MessageBox.Show используется для отображения окна сообщения и возвращения результата. Результат показывает, как пользователь закрыл окно сообщения:
Когда пользователь нажимает кнопки в нижней части окна сообщения, возвращается соответствующий результат MessageBoxResult. Однако, если пользователь нажимает клавишу ESC или кнопку Закрыть (№ 2 на рисунке окна сообщения), результат окна сообщения зависит от параметров кнопки:
Параметры кнопок | Результат для кнопки ESC или Закрыть |
---|---|
Ok | Ok |
OkCancel | Cancel |
YesNo | Клавиша клавиатуры ESC и кнопка Закрыть отключены. Пользователю необходимо нажать Yes (Да) или No (Нет). |
YesNoCancel | Cancel |
Дополнительные сведения об использовании окон сообщений см. в описании MessageBox и примере MessageBox.
Источник
How to show an unhandled exception window in WPF
In the previous post, we created a base class that listens for unhandled exceptions in our .NET application. In this post we will derive from that class to show an error window for every unhandled exception that occurs in our program.
The WindowExceptionHandler class
Let’s start with the WindowExceptionHandler. This class inherits from GlobalExcptionHanderBase (which we implemented in the previous post) and implements the OnUnhandledException(Exception) method. This method will be called whenever there is an unhandled exception in our application.
Inside that method, we create an instance of the ExceptionWindow class, set its DataContext property and display it by calling exceptionWindow.Show().
Notice that the code is wrapped inside a Dispatcher.BeginInvoke(..) call. This is because the OnUnhandledException(..) method might be called from a thread other then the main thread. To make sure that our ExceptionWindow is created and shown on the main (dispatcher) thread we post our exception window creation with BeginInvoke(..) to be executed on the next dispatcher frame.
Creating the exception window
The content of an exception error window will be very different depending on your use case. If the window is for development purpose only, we probably want as much technical information about the exception as possible. If its presented to the non technical user, it might be better to just let them know that something went wrong without any technical details at all.
For the purpose of this post, we create a exception window that hides the details behind an expander control. The following screenshot shows the expanded window:
Screenshot of the expanded exception window
Here is the XAML code that creates the above window
To access the exceptions details via databinding the DataContext property of the window is set to an instance of the ExceptionWindowVM class.The view model holds the Exception object and its type as a string property:
We could have used the Exception object itself as DataContext. But there is no Type property on the Exception class to bind to. There are of course other ways to display the type string but wrapping the exception in a view model makes the code easily extendable for future requirements.
To setup the WindowExceptionHandler in our application we just need to new up an instance of the class somewhere. This is typically done in a place where all the wiring of the application happens. In this sample project its simply the App’s constructor in App.xaml.cs:
Thats all the code we need to show an exception window for every unhandled exception in our application!
Handle exception or exit application?
Once the exception windows shows up, there was an unhandled exception in our application. Which options do we give to the user now? Can she just close the exception window and use our application like before or is it better to shut down the application?
The application might work as expected even after an unhandled exception. But we have no way to proof this inside our global exception handler. Since the exception was not handled by our applications code, it might have corrupted the application state. Letting the user work with our application in this situation can be very dangerous. In the best case the app might work just like before, or there might be further exceptions. But it might also leave our application in a state where the user can do things she might not be allowed to or …, … the possibilities for error are endless.
In case of an unhandled exception in a real world application, we have no other choice then to shut down the application. This is why there is an “Exit application” button instead of an “OK” button on the exception window. There is also an event handler for the Closed event of the exception window to exit the app when the user presses the X on button.
A sample project
The MainWindow of the sample project for this post comes with a few buttons that throw different kind of exceptions. The simplest one is a normal exception that is thrown on the main thread. Then there is a button that produces an UnobservedTaskException on the finalizer thread and there are the bad ones that throw exceptions on worker threads.
As explained in the previous post, exceptions on threads other then the main thread cannot be handled and will terminate the process. This means our exception window wont work for these exceptions.
To make it work, we need to catch all exceptions on worker threads and re-throw them on to the main (dispatcher) thread. The code behind the last button “Throw on another Thread handled” does exactly that.
It wraps the business logic inside a Try-Catch block and throws the exception on the dispatcher.
If you use the Task or Task for asynchronous programming in your application, a lot of these problems are handled for you. Exceptions in async methods are catched by the framework and are stored in the returning Task object. Awaiting the task will then re-throw the exception on the calling thread. Unless you are using async void… In an async void method there is no Task object returned so the exception cannot be stored and will be thrown on whatever thread the method’s code is executed. This might not be the main thread. So do not create async void methods, but if you do, wrap the await part in a Try-Catch block and re-throw the exception on the dispatcher as above. Here is a handy ThrowOnDispatcher() extension method for this situation:
Summary
We used the GobalExceptionHandlerBase class from the previous post to create a WindowExceptionHandler that shows an exception window for every unhandled exception that occurs in our application.
We saw that it is important to shut down the application after an unhandled exception because we might have corrupted the application state and that exceptions on worker threads will terminate our application without a chance to display an error to the user.
All the code for this post can be found on this Github repository
Источник
Приветствую!
В статье посвященной моему профайлеру для Entity Framework-a, я вкратце описал примененную мной форму для сообщения пользователю об исключительной ошибке в приложении. После оценки количества скачиваний примера кода, было решено выделить этот пример в отдельный проект, а также добавить поддержку WPF приложений.
Исходники библиотеки вместе с примерами опубликованы на CodePlex под свободной лицензией MIT: https://uiexceptionhandler.codeplex.com/
Подробности под катом.
Введение
Всем известно, что приложения периодически падают по самым разным причинам, при этом, крайне желательно показывать пользователю дружественное сообщение об ошибке в приложении, вместо стандартного сообщения Windows.
Что получилось
При подключенной библиотеке, в случае падения приложения будет показано следующие сообщение с просьбой добавить описание шагов которые привели к ошибке и свой email для ответа, при этом текст ошибки сохраняется в лог файл.
При клике по кнопке «Error detail information» выводиться дополнительная информация об ошибке:
Кнопка Debug позволяет подключить отладчик Visual Studio.
Кнопка «Send to Developer» отправляет письмо на почту разработчику. В случае ошибки отправки сообщения, пользователю будет предложено самому отправить лог файл разработчику на почту.
Отправленное разработчику сообщение придет в таком виде:
Использование
1. Забрать последнюю версию кода https://uiexceptionhandler.codeplex.com/SourceControl/latest
2. Собрать в Release mode.
3. Из папки «UIExceptionHandlerLibsDeploy» подключить в проект библиотеку UIExceptionHandlerWinForms.dll в случае WinForms приложения и UIExceptionHandlerWPF.dll в случае WPF приложения.
4. Инициализировать путем вызова статического метода с рядом параметров:
UIException.Start(
string serverSmtp,
int portSmtp,
string passwdSmtp,
string userSmtp,
string programmerEmail,
string fromEmail,
string subject
)
Как это работает
Статический метод UIException.Start подписывает метод HandleError на событие AppDomain.CurrentDomain.UnhandledException:
AppDomain.CurrentDomain.UnhandledException += (sender, e) => HandleError((Exception)e.ExceptionObject);
Метод HandleError:
private static void HandleError(Exception exception)
{
try
{
// запускаем обработчик формы и передаем ему ссылку на форму наследованную от интерфейса IErrorHandlerForm
new ErrorHandlerController(exception, new ErrorHandlerForm()).Run();
}
catch (Exception e)
{
// сохраняем ошибку в лог файл
LogHelper.Logger.Error(e);
// в случае ошибки обработки выводим сообщение с просьбой отправить лог файл разработчику на почту
MessageBox.Show("Error processing exception. Please send log file " + LogHelper.ExceptionLogFileName + " to developer: " + Settings.ProgrammerEmail + " rn Exception:" + e);
// спрашиваем нужно ли подключить отладчик
if (MessageBox.Show("Attach debugger? n Only for developer!!!", "Debugging...", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
{
Debugger.Launch();
throw;
}
}
finally
{
// обязательно завершаем приложение чтобы windows не вывела стандартное сообщение об ошибке
Environment.Exit(1);
}
}
Интерфейс IErrorHandlerForm:
public interface IErrorHandlerForm
{
event Action OnSendButtonClick;
event Action OnShowErrorLinkClick;
event Action OnLogFileLinkClick;
event Action OnDebugButtonClick;
// меняет высоту формы
void SetHeight(int height);
// задает подробное сообщение об ошибке
string ExceptionInfoText { get; set; }
// получает текст из поля дополнительной информации введенной пользователем
string ExceptionDetailText { get; set; }
// email пользователя для ответа
string ReplyEmail { get; }
void ShowExceptionInfoTextBox(bool isShow);
// выводит информационное сообщение
void ShowInfoMessageBox( string text, string caption);
// выводит диалоговое сообщение
bool ShowQuestionDialog( string text, string caption);
// показывает окно в режиме диалога! необходимо чтобы приложение дожидалось закрытия окна и завершилось в finaly
void ShowViewDialog();
void UpdateContactEmail(string contactEmail);
}
В качестве библиотеки для логгирования используется NLog. Для того чтобы избежать появления лишних xml файлов, вся конфигурация Nlog-а делается в коде:
private static void ConfigureNlog()
{
var config = new LoggingConfiguration();
var fileTarget = new FileTarget();
config.AddTarget("file", fileTarget);
fileTarget.Layout = @"${longdate} ${message}";
fileTarget.FileName = "${basedir}/" + ExceptionLogFileName;
var rule2 = new LoggingRule("*", LogLevel.Trace, fileTarget);
config.LoggingRules.Add(rule2);
LogManager.Configuration = config;
}
Чтобы добиться максимальной простой интеграции в проект, я решил все используемые сборки объединить в одну библиотеку. Делается это при помощи приложения ILMerge, путем добавления скрипта в post-build событие:
if $(ConfigurationName) == Release (
"$(SolutionDir)ILMergeILMerge.exe" /out:"$(SolutionDir)Deploy$(TargetFileName)" "$(TargetDir)*.dll" /target:dll /targetplatform:v4,C:WindowsMicrosoft.NETFramework64v4.0.30319 /wildcards
)
Послесловие
Данное решение было написано для достаточно крупного проекта, применяется уже более 2-х лет, значительно улучшив процесс исправления ошибок, поскольку о каждом падении приложения узнаешь моментально, без дополнительной нотификации от пользователя.
Надеюсь это все будет кому-то полезно!
Всем спасибо за внимание!
Диалоговые окна:
WPF предлагает на выбор несколько видов диалоговых окон для приложений, но самым простым является MessageBox. Единственной его целью является отображение сообщений пользователю, и один/несколько вариантов выбора.
Использование MessageBox осуществляется с помощью вызова статического метода Show(), который может принимать на входе несколько различных параметров, необходимых для реализации запланированного Вами поведения. Мы рассмотрим некоторые варианты перегрузок данного метода, которые будут подкреплены кодом MessageBox.Show() и скриншотами. В конце главы Вы найдете полный код примера, который позволит Вам протестировать различные варианты использования MessageBox.
В своей самой простой форме, MessageBox принимает один параметр (сообщение для отображения пользователю):
MessageBox.Show("Hello, world!");
MessageBox с заголовком
Предыдущий пример не является особо полезным. Ситуацию может улучшить заголовок диалогового окна. К счастью, второй возможный параметр метода Show() позволяет определить заголовок:
MessageBox.Show("Hello, world!", "My App");
MessageBox с дополнительными кнопками
По умолчанию MessageBox имеет только одну «Ok» кнопку, но это можно легко изменить, если Вы вдруг захотите дать пользователю возможность ответа, а не просто показать какую-либо информацию. Также, обратите внимание, как с помощью n осуществляется поддержка многострочных сообщений в MessageBox:
MessageBox.Show("This MessageBox has extra options.nnHello, world?", "My App", MessageBoxButton.YesNoCancel);
Тем, какие кнопки отображать, Вы управляете, используя значение из перечисления MessageBoxButton. В него входят кнопки Yes, No и Cancel. Данные значения могут использоваться в следующих комбинациях:
- OK
- OKCancel
- YesNoCancel
- YesNo
Теперь Вам необходимо обработать варианты выбора пользователя. К счастью, метод MessageBox.Show() возвращает значение из перечисления MessageBoxResult. Вот пример:
MessageBoxResult result = MessageBox.Show("Would you like to greet the world with a "Hello, world"?", "My App", MessageBoxButton.YesNoCancel);
switch(result)
{
case MessageBoxResult.Yes:
MessageBox.Show("Hello to you too!", "My App");
break;
case MessageBoxResult.No:
MessageBox.Show("Oh well, too bad!", "My App");
break;
case MessageBoxResult.Cancel:
MessageBox.Show("Nevermind then...", "My App");
break;
}
Проверяя значение-результат метода MessageBox.Show(), становится возможной обработка пользовательского выбора, как видно из скриншотов.
MessageBox с иконкой
С помощью четвертого параметра, MessageBox может отображать иконки «по умолчанию» слева от текста сообщения:
MessageBox.Show("Hello, world!", "My App", MessageBoxButton.OK, MessageBoxImage.Information);
С использованием перечисления MessageBoxImage Вы можете выбирать между несколькими иконками, подходящими под определенную ситуацию. Вот полный список:
- Asterisk (звезда)
- Error (ошибка)
- Exclamation (восклицательный знак)
- Hand (рука)
- Information (информация)
- None (без иконки)
- Question (знак вопроса)
- Stop (стоп)
- Warning (внимание)
В основном названия этих иконок соответствуют содержанию, но Вы с легкостью можете поэкспериментировать с помощью статьи на MSDN, в которой проиллюстрировано использование всех иконок:
http://msdn.microsoft.com/en-us/library/system.windows.messageboximage.aspx
MessageBox с выбором по умолчанию
MessageBox выберет кнопку по умолчанию, при нажатии на Enter. Например, если вы отображаете диалоговое окно с кнопками «Yes» и «No», первая будет определена как выбор по умолчанию. Вы можете изменить это поведение, используя пятый параметр метода MessageBox.Show():
MessageBox.Show("Hello, world?", "My App", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);
Обратите внимание как на скриншоте приподнята кнопка «No» (выделена как выбранная).
Она сработает при нажатии на Enter или Space.
Полный пример
Как было обещано в начале главы, вот полный пример:
<Window x:Class="WpfTutorialSamples.Dialogs.MessageBoxSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MessageBoxSample" Height="250" Width="300">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel.Resources>
<Style TargetType="Button">
<Setter Property="Margin" Value="0,0,0,10" />
</Style>
</StackPanel.Resources>
<Button Name="btnSimpleMessageBox" Click="btnSimpleMessageBox_Click">Simple MessageBox</Button>
<Button Name="btnMessageBoxWithTitle" Click="btnMessageBoxWithTitle_Click">MessageBox with title</Button>
<Button Name="btnMessageBoxWithButtons" Click="btnMessageBoxWithButtons_Click">MessageBox with buttons</Button>
<Button Name="btnMessageBoxWithResponse" Click="btnMessageBoxWithResponse_Click">MessageBox with response</Button>
<Button Name="btnMessageBoxWithIcon" Click="btnMessageBoxWithIcon_Click">MessageBox with icon</Button>
<Button Name="btnMessageBoxWithDefaultChoice" Click="btnMessageBoxWithDefaultChoice_Click">MessageBox with default choice</Button>
</StackPanel>
</Window>
using System;
using System.Windows;
namespace WpfTutorialSamples.Dialogs
{
public partial class MessageBoxSample : Window
{
public MessageBoxSample()
{
InitializeComponent();
}
private void btnSimpleMessageBox_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Hello, world!");
}
private void btnMessageBoxWithTitle_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Hello, world!", "My App");
}
private void btnMessageBoxWithButtons_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("This MessageBox has extra options.nnHello, world?", "My App", MessageBoxButton.YesNoCancel);
}
private void btnMessageBoxWithResponse_Click(object sender, RoutedEventArgs e)
{
MessageBoxResult result = MessageBox.Show("Would you like to greet the world with a "Hello, world"?", "My App", MessageBoxButton.YesNoCancel);
switch(result)
{
case MessageBoxResult.Yes:
MessageBox.Show("Hello to you too!", "My App");
break;
case MessageBoxResult.No:
MessageBox.Show("Oh well, too bad!", "My App");
break;
case MessageBoxResult.Cancel:
MessageBox.Show("Nevermind then...", "My App");
break;
}
}
private void btnMessageBoxWithIcon_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Hello, world!", "My App", MessageBoxButton.OK, MessageBoxImage.Information);
}
private void btnMessageBoxWithDefaultChoice_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Hello, world?", "My App", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);
}
}
}
This article has been fully translated into the following languages:
-
Chinese
-
Czech
-
Danish
-
French
-
German
-
Hungarian
-
Italian
-
Japanese
-
Korean
-
Polish
-
Portuguese
-
Russian
-
Slovak
-
Spanish
-
Ukrainian
-
Vietnamese
Is your preferred language not on the list? Click here to help us translate this article into your language!
Hi,
You can implement Binding Validation in WPF.
Method one: throw ApplicationException
public partial class ExceptionValidationRule_sample : Window { public ExceptionValidationRule_sample() { InitializeComponent(); } } public class ExceptionValidationRule_sample_ViewModel { private string _name; public string Name { get { return _name; } set { _name = value; // your validation rule if (String.IsNullOrEmpty(value)) { throw new ApplicationException("Name is mandatory."); } } } }
<Window.DataContext> <local:ExceptionValidationRule_sample_ViewModel/> </Window.DataContext> <StackPanel> <TextBox Margin="10,10,200,10" > <TextBox.Style> <Style TargetType="{x:Type TextBox}"> <Setter Property="Validation.ErrorTemplate"> <Setter.Value> <ControlTemplate> <DockPanel LastChildFill="True"> <TextBlock DockPanel.Dock="Right" Foreground="Red" FontSize="12pt" Text="{Binding ElementName=MyAdorner,Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"> </TextBlock> <Border BorderBrush="Green" BorderThickness="1"> <AdornedElementPlaceholder Name="MyAdorner" /> </Border> </DockPanel> </ControlTemplate> </Setter.Value> </Setter> </Style> </TextBox.Style> <TextBox.Text> <Binding Path="Name" UpdateSourceTrigger="PropertyChanged"> <Binding.ValidationRules> <ExceptionValidationRule /> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox> </StackPanel>
You can also custom rule by implement the ValitaionRule class.
public partial class ValidationRule_sample : Window { public ValidationRule_sample() { InitializeComponent(); } } public class ValidationRule_sample_ViewModel { private string _name; public string Name { get { return _name; } set { _name = value; } } } public class StringRangeValidationRule : ValidationRule { private int _minimumLength = -1; private int _maximumLength = -1; private string _errorMessage; public int MinimumLength { get { return _minimumLength; } set { _minimumLength = value; } } public int MaximumLength { get { return _maximumLength; } set { _maximumLength = value; } } public string ErrorMessage { get { return _errorMessage; } set { _errorMessage = value; } } public override System.Windows.Controls.ValidationResult Validate(object value, CultureInfo cultureInfo) { System.Windows.Controls.ValidationResult result = new System.Windows.Controls.ValidationResult(true, null); string inputString = (value ?? string.Empty).ToString(); if (inputString.Length < this.MinimumLength || (this.MaximumLength > 0 && inputString.Length > this.MaximumLength)) { result = new System.Windows.Controls.ValidationResult(false, this.ErrorMessage); } return result; } }
<Window.DataContext> <local:ValidationRule_sample_ViewModel /> </Window.DataContext> <StackPanel Grid.Column="0"> <!--LostFocus--> <TextBox Margin="10,10,200,10" > <TextBox.Style> <Style TargetType="{x:Type TextBox}"> <Setter Property="Validation.ErrorTemplate"> <Setter.Value> <ControlTemplate> <DockPanel LastChildFill="True"> <TextBlock DockPanel.Dock="Right" Foreground="Red" FontSize="12pt" Text="{Binding ElementName=MyAdorner,Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"> </TextBlock> <Border BorderBrush="Green" BorderThickness="1"> <AdornedElementPlaceholder Name="MyAdorner" /> </Border> </DockPanel> </ControlTemplate> </Setter.Value> </Setter> </Style> </TextBox.Style> <TextBox.Text> <Binding Path="Name" UpdateSourceTrigger="LostFocus"> <Binding.ValidationRules> <local:StringRangeValidationRule MinimumLength="1" ErrorMessage="A name is required." /> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox> <!--PropertyChanged--> <TextBox Margin="10,10,200,10" > <TextBox.Style> <Style TargetType="{x:Type TextBox}"> <Setter Property="Validation.ErrorTemplate"> <Setter.Value> <ControlTemplate> <DockPanel LastChildFill="True"> <TextBlock DockPanel.Dock="Right" Foreground="Red" FontSize="12pt" Text="{Binding ElementName=MyAdorner,Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"> </TextBlock> <Border BorderBrush="Green" BorderThickness="1"> <AdornedElementPlaceholder Name="MyAdorner" /> </Border> </DockPanel> </ControlTemplate> </Setter.Value> </Setter> </Style> </TextBox.Style> <TextBox.Text> <Binding Path="Name" UpdateSourceTrigger="PropertyChanged"> <Binding.ValidationRules> <local:StringRangeValidationRule MinimumLength="1" ErrorMessage="A name is required." /> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox> <!--Explicit--> <TextBox Margin="10,10,200,10" > <TextBox.Style> <Style TargetType="{x:Type TextBox}"> <Setter Property="Validation.ErrorTemplate"> <Setter.Value> <ControlTemplate> <DockPanel LastChildFill="True"> <TextBlock DockPanel.Dock="Right" Foreground="Red" FontSize="12pt" Text="{Binding ElementName=MyAdorner,Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"> </TextBlock> <Border BorderBrush="Green" BorderThickness="1"> <AdornedElementPlaceholder Name="MyAdorner" /> </Border> </DockPanel> </ControlTemplate> </Setter.Value> </Setter> </Style> </TextBox.Style> <TextBox.Text> <Binding Path="Name" UpdateSourceTrigger="Explicit"> <Binding.ValidationRules> <local:StringRangeValidationRule MinimumLength="1" ErrorMessage="A name is required." /> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox> </StackPanel>
Method two: IDataErrorInfo
public IDataErrorInfo_sample() { InitializeComponent(); Customer cus = new Customer(); this.DataContext = cus; cus.Name = "Bob Ding"; } public class Customer : IDataErrorInfo { private string _name; [Display(Name = "Name")] [RegularExpression(@"^(?=.*[a-z])(?=.*[A-Z])(?=.*d).+$")] public string Name { get { return _name; } set { _name = value; } } public string Error { get { return this[string.Empty]; } } public string this[string propertyName] { get { string result = string.Empty; propertyName = propertyName ?? string.Empty; if (propertyName == string.Empty || propertyName == "Name") { if (string.IsNullOrEmpty(this.Name)) { result = "Name cannot be blank!"; } } return result; } } }
<StackPanel> <TextBox Margin="10,10,200,10" Text="{Binding Path=Name, Mode=TwoWay, NotifyOnValidationError=True, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=true}"> <TextBox.Style> <Style TargetType="{x:Type TextBox}"> <Setter Property="Validation.ErrorTemplate"> <Setter.Value> <ControlTemplate> <DockPanel LastChildFill="True"> <TextBlock DockPanel.Dock="Right" Foreground="Red" Margin="5,0,5,0" Text="*"/> <Border BorderBrush="Red" BorderThickness="1"> <AdornedElementPlaceholder Name="ph"/> </Border> </DockPanel> </ControlTemplate> </Setter.Value> </Setter> <Style.Triggers> <Trigger Property="Validation.HasError" Value="true"> <Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}"/> </Trigger> </Style.Triggers> </Style> </TextBox.Style> </TextBox> <TextBox></TextBox> </StackPanel>
You can refer these links:
https://docs.microsoft.com/en-us/dotnet/framework/wpf/data/how-to-implement-binding-validation
Validation in WPF
Validation in Windows Presentation Foundation
Best Regards,
Bob
MSDN Community Support
Please remember to click «Mark as Answer» the responses that resolved your issue, and to click «Unmark as Answer» if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to
MSDN Support, feel free to contact MSDNFSF@microsoft.com.
In this post, I will show how you can present user input validation errors to the user. By default, WPF shows a red border around the TextBox
when the entered value is invalid. But in this case, our user has no idea what is wrong with entered data. We need to inform the user by providing an error message on the view.
To show you available option I created a sample project. You can find it under the link: https://github.com/kmatyaszek/WPFValidationDisplayErrors
In our sample project, we have four TextBox
elements. Each of them presents a different style of presenting the occurred error to the user. When an error occurs (user entered value equals test) on the data binding the attached property Validation.HasError
property is set to true on the target element of the data binding process (in our case it’s TextBox
element). So we can use this property to indicate if the value entered by the user is invalid. We also can use Validation.Errors
attached property to retrieve error message.
Below you can see the output of our sample project. As you can see when I typed value test to each of the TextBox
each of them shows me an error message in the different form.
In this example, I focused on presenting the error message to the user so I decided to use the ValidatesOnExceptions
mechanism (to read more about this please go to the following link: WPF Validation — Using ValidatesOnExceptions). Let’s look at the source code especially on XAML code.
<Window x:Class="WPFValidationDisplayErrors.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="400">
<Window.Resources>
<Style TargetType="Label">
<Setter Property="Margin" Value="5" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style x:Key="DefaultTextBoxStyle" TargetType="TextBox">
<Setter Property="Margin" Value="5" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style x:Key="ToolTipWithErrorMessageOnErrorStyle" TargetType="TextBox" BasedOn="{StaticResource DefaultTextBoxStyle}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="RedBackgroundOnErrorStyle" TargetType="TextBox" BasedOn="{StaticResource ToolTipWithErrorMessageOnErrorStyle}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="Background" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="CustomErrorControlOnErrorStyle" TargetType="TextBox" BasedOn="{StaticResource DefaultTextBoxStyle}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<StackPanel>
<AdornedElementPlaceholder x:Name="placeholder" />
<TextBlock FontSize="11" FontStyle="Italic" Foreground="Red"
Text="{Binding ElementName=placeholder, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid Grid.IsSharedSizeScope="True">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Labels" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Content="Default:" />
<TextBox Grid.Column="1"
Text="{Binding Path=Default, Mode=TwoWay, ValidatesOnExceptions=True, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource DefaultTextBoxStyle}" />
<Label Content="ToolTip:" Grid.Row="1" />
<TextBox Grid.Column="1" Grid.Row="1"
Text="{Binding Path=ToolTip, Mode=TwoWay, ValidatesOnExceptions=True, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource ToolTipWithErrorMessageOnErrorStyle}" />
<Label Content="Background and ToolTip:" Grid.Row="2" />
<TextBox Grid.Column="1" Grid.Row="2"
Text="{Binding Path=Background, Mode=TwoWay, ValidatesOnExceptions=True, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource RedBackgroundOnErrorStyle}" />
<Label Content="Custom error template:" Grid.Row="3" />
<TextBox Grid.Column="1" Grid.Row="3"
Text="{Binding Path=CustomError, Mode=TwoWay, ValidatesOnExceptions=True, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource CustomErrorControlOnErrorStyle}" />
</Grid>
</Window>
As you can see in the above code snippet we defined TextBox
styles in the Window resources section. As I mentioned before to indicate if we should show error message we’re using attached Validation.HasError
property. In the first row is presented default behavior of the validation errors in WPF, it only shows a red border around the TextBox
. In the second row, I created a custom style to show an error message in the tooltip. In the third row, I added the background color if the value is invalid. And in the last row, I created custom error template to show error message right below TextBox
.
Introduction
A message box is a dialog box that displays an alert or a message or also lets the user have some options to choose from. A simple message box has an OK button and looks as in Figure 1.
Figure 1
A message box can have a title and multiple options such as Yes, No, and Cancel. A message box can also have some input control to take input from a user.
MessageBox Class
The MessageBox class in WPF represents a modal message box dialog, which is defined in the System.Windows namespace. The Show static method of the MessageBox is the only method that is used to display a message box. The Show method returns a MessageBoxResult enumeration that has the values None, OK, Cancel, Yes, and No. We can use MessageBoxResult to determine what button was clicked on a MessageBox and take an appropriate action.
Show method has 13 overloaded methods. Here are the code samples and their results of these 13 overloaded methods.
Simple MessageBox
A simple MessageBox shows a message and only has an OK button. Clicking on the OK button closes the MessageBox. The following line of code uses the Show method to display a message box with a simple message:
- MessageBoxResult result = MessageBox.Show(«Hello MessageBox»);
The MessageBox generated by the line of code above is a modal dialog with an OK button on it and looks as in Figure 2.
Figure 2
MessageBox with Title
A MessageBox can have a title. The first parameter of the Show method is a message string and the second parameter is title string of the dialog. The following code snippet creates a MessageBox with a message and a title.
- MessageBoxResult result = MessageBox.Show(«Hello MessageBox», «Confirmation»);
The output looks like Figure 3.
Figure 3
MessageBox with Owner
A MessageBox does not have an owner by default but you can specify an owner by setting the following code. In this code, the first parameter is the current window.
- MessageBoxResult result = MessageBox.Show(this, «Hello MessageBox»);
MessageBoxButton Enumeration
The MessageBoxButton enumeration is responsible for showing various buttons on the dialog. It has the following values:
- OK — OK button is displayed
- OKCancel — OK and Cancel buttons are displayed
- YesNo — Yes and No buttons are displayed
- YesNoCancel — Yes, No, and Cancel buttons are displayed
MessageBox with Title, Yes and No Buttons
A MessageBox can be used to ask the user a question and have Yes and No buttons. Based on the user selection (Yes or No), you can execute the appropriate code. The third parameter of the Show method is a MessageBoxButton enumeration.
The following code snippet creates a MessageBox with a message, a title, and two Yes and No buttons.
- if (MessageBox.Show(«Do you want to close this window?»,
- «Confirmation», MessageBoxButton.YesNo) == MessageBoxResult.Yes)
- {
- }
- else
- {
- }
The output looks as in Figure 4.
Figure 4
MessageBox with Title, Yes, No and Cancel Buttons
The following code snippet creates a MessageBox with a message, a title, and two Yes, No, and Cancel buttons.
- MessageBoxResult result = MessageBox.Show(«Do you want to close this window?»,
- «Confirmation», MessageBoxButton.YesNoCancel);
- if (result == MessageBoxResult.Yes)
- {
- }
- elseif (result == MessageBoxResult.No)
- {
- }
- else
- {
- }
The output looks as in Figure 5.
Figure 5
MessageBox with Title, Icon, Yes and No Buttons
A MessageBox also allows you to place an icon that represents the message and comes with some built-in icons. The MessageBoxImage enumeration represents an icon. Here is a list of MessageBoxImage enumeration values that represent the relative icons.
- None
- Hand
- Question
- Exclamation
- Asterisk
- Stop
- Error
- Warning
- Information
The following code snippet creates a MessageBox with a message, a title, and two Yes and No buttons and an icon.
- string message = «Are you sure?»;
- string caption = «Confirmation»;
- MessageBoxButton buttons = MessageBoxButton.YesNo;
- MessageBoxImage icon = MessageBoxImage.Question;
- if (MessageBox.Show(message, caption, buttons, icon) == MessageBoxResult.OK)
- {
- }
- else
- {
- }
The output looks as in Figure 6.
Figure 6
MessageBox with Title, OK, and Cancel Buttons
By simply using MessageBoxButton.YesNo in the Show method, a MessageBox with OK and Cancel buttons is created. The following code snippet creates a MessageBox with a message, a title, and two OK and Cancel buttons:
- if (MessageBox.Show(«Do you want to close this window?»,
- «Confirmation», MessageBoxButton.YesNo) == MessageBoxResult.Yes)
- {
- }
- else
- {
- }
The output looks as in Figure 7.
Figure 7
MessageBox with Title, Icon, OK, and Cancel Buttons
The following code snippet creates a MessageBox with a message, a title, icon, and two OK and Cancel buttons:
- MessageBoxResult result = MessageBox.Show(this, «If you close this window, all data will be lost.»,
- «Confirmation», MessageBoxButton.OKCancel, MessageBoxImage.Warning);
- if (result == MessageBoxResult.OK)
- {
- }
- else
- {
- }
The output looks as in Figure 8.
Figure 8
Mixing it up
These are not the only options. You can mix any of these options to show whatever kind of MessageBox you want to display.
Customizing MessageBox
Even though it looks like WPF MessageBox is a part of System.Windows namespace, it is just a wrapper of the Win32 API and this is why you can’t use it at design-time in XAML or customize it. To customize a MessageBox, you will be better off creating your own Custom Control. See my articles on how to build Custom Controls in WPF by searching this website for custom controls in WPF.
Summary
In this tutorial, we saw various avatars (reincarnations) of MessageBox in WPF.