Share via


WPF Exception Message Box

Introduzione

Questo è il primo di una serie di articoli che mostreranno suggerimenti, librerie e trucchi per migliorare le proprie applicazioni in WPF. Una delle mie maggiori competenze è quella dello sviluppo in ambienti Desktop e al termine dello sviluppo faccio un giro su Nuget, Github, Codeplex, Codeproject a cercare qualcosa che mi desse quel valore aggiunto all’applicazione. Altri sono dovuti alla necessità di risolvere un determinato problema e quindi le ho trovate su Internet. Così ne ho provati alcuni per voi che man mano vi illustrerò. Premetto che molte librerie sono vecchie e non più aggiornate, ma è giusto per mettervi a conoscenza dell’esistenza di queste stesse librerie.

Il primo che andremo a vedere è il WPF Exception MessageBox.

Lavoriamo con il controllo

Lo troviamo a questo indirizzo: http://exceptionmessagebox.codeplex.com/

L’ultimo aggiornamento è del 2011 ma poco importa. Quello che importa è che potremo creare delle finestre personalizzate in caso di errore con la scritta che vogliamo noi.

Ovviamente affinché possiamo fare la chiamata alla funzione che visualizzerà la finestra personalizzata dovremo mettere un blocco Try Catch e il codice che chiama la finestra nella parte del Catch.

Per poter usare la libreria, il mio consiglio è quello di aggiungere al progetto un nuovo progetto (che è la libreria) e quindi aggiungere la Reference nel progetto principale.

Vediamo come fare.

Apriamo Visual Studio 2015 e creiamo un nuovo progetto in C# chiamato WpfExceptionMessageBox.

Aggiungiamo a questo punto un progetto esistente, andiamo a prendere il progetto della libreria scaricata da Codeplex (che io consiglierei di copiarlo nella stessa cartella che contiene il file SLN.

Se dovesse chiedere l’aggiornamento, lasciamoglielo fare.

Compiliamo prima la libreria in modo che venga creata la dll.

A questo punto aggiungiamo la Reference nel nostro progetto principale:

A questo punto siamo pronti per inserire nei nostri gestori d’errore la nuova finestra delle Eccezioni.

Creiamo un pulsante e nel codice ci mettiamo un errore apposta.

Creiamo quindi il blocco Try Catch e all’interno ci metteremo la chiamata alla nuova finestra di gestione delle eccezioni.

Un esempio tipico di codice “normale” potrebbe essere questo:

        private void MakeExceptionButton_Click(object sender, RoutedEventArgs e)

        {

            object o2 = null;

            try

            {

                int i2 = (int)o2;   // Error

            }

            catch (Exception ex)

            {

                MessageBox.Show(ex.Message);

            }

      

        }

A questo punto andremo a sostituire la MessageBox con la chiamata alla libreria:

ExceptionMessageBox<ExceptionMessageBoxView>.Show("Si è verificata un’eccezione.", ex);

Alla fine questo è il codice del pulsante:

        private void MakeExceptionButton_Click(object sender, RoutedEventArgs e)

        {

            object o2 = null;

            try

            {

                int i2 = (int)o2;   // Error

            }

            catch (Exception ex)

            {

                ExceptionMessageBox<ExceptionMessageBoxView>.Show("Si è verificata un’eccezione.", ex);

            }

        }

Ovviamente negli using andremo ad aggiungere la seguente riga:

using ExceptionMessageBoxLibrary;

Possiamo ora lanciare il progetto, clicchiamo poi sul pulsante e otteniamo questo:

Cliccando su Details la finestra appare ora così:

Cliccando OK la finestra si chiude e grazie al blocco Try Catch abbiamo ottenuto lo stesso tipo di finestra di un’eccezione, ma questa volte il programma non viene terminato.

Struttura della libreria

Vediamo com’è strutturata la libreria e come possiamo modificarla o personalizzarla.

 Apriamo il file ExceptionMessageBoxView.xaml e questo è l’XAML:

 <Window x:Class="ExceptionMessageBoxLibrary.ExceptionMessageBoxView"

     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

     Title="{Binding Caption}" SizeToContent="Height" Width="450" ShowInTaskbar="False" ResizeMode="NoResize" Closing="Window_Closing" >   

     <Grid Name="Image" Margin="5">

         <Grid.ColumnDefinitions>

             <ColumnDefinition Width="80" />

             <ColumnDefinition Width="*" />

         </Grid.ColumnDefinitions>

         <Grid.RowDefinitions>

             <RowDefinition Height="90" />            

             <RowDefinition Height="Auto" />

         </Grid.RowDefinitions>

         

         <Image Name="imageError" Stretch="Fill" Source="/ExceptionMessageBox;component/Resources/Images/error.png" Height="32" Width="32" Margin="0,25,0,0" VerticalAlignment="Top"/>

        <TextBlock Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="2" Name="messageTextBlock" TextWrapping="Wrap" TextTrimming="CharacterEllipsis" Text="{Binding UserMessage}" />

        <Expander Grid.ColumnSpan="2" Grid.Row="1" Header="Details" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="0" Name="showDetailExpander" >

             <Grid Margin="0,4,0,0" Height="200">

                 <TextBox Grid.Row="2" Grid.ColumnSpan="2" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible"

                  Margin="0" Name="exceptionTextBlock" Text="{Binding ExceptionDetail}" IsReadOnly="True" AcceptsReturn="True" />

             </Grid>

         </Expander>

        <StackPanel Grid.Row="1" Grid.Column="1" VerticalAlignment="Top" Orientation="Horizontal" HorizontalAlignment="Right" Height="26" Margin="0">

             <Button Grid.Row="1" Grid.Column="1" Name="okButton" Content="OK" Width="74" Height="22" Margin="2" Visibility="{Binding OKVisibility}" Click="okButton_Click"></Button>

             <Button Grid.Row="1" Grid.Column="1" Name="yesButton" Content="Yes" Width="74" Height="22" Margin="2" Visibility="{Binding YesVisibility}" Click="yesButton_Click"></Button>

            <Button Grid.Row="1" Grid.Column="1" Name="noButton" Content="No" Width="74" Height="22" Margin="2" Visibility="{Binding NoVisibility}" Click="noButton_Click"></Button>

             <Button Grid.Row="1" Grid.Column="1" Name="cancelButton" Content="Cancel" Width="74" Height="22" Margin="2" Visibility="{Binding CancelVisibility}" Click="cancelButton_Click"></Button>

         </StackPanel>  

         

     </Grid>

 </Window>

Come potete vedere nulla di complicato: abbiamo l’icona dell’errore, una TextBox che contiene il testo dell’errore, un Expander che contiene i dettagli dell’errore e infine , 4 pulsanti che cambieranno visibility in base al topo dell’errore.

La libreria usa il pattern MVVM e vediamo come funziona.

Al momento che si verifica l’eccezione, viene chiamata la funzione ShowCore avente come parametri il messaggio dell’errore, l’eccezione, i tasti da visualizzare e quello che di default deve essere selezionato.

Ecco la chiamata alla funzione:

return ShowCore(p_message, p_exception, defaultCaption, MessageBoxButton.OK, null);

Quello che segue è il codice di ShowCore:

            if (p_message == null)

            {

                throw new ArgumentNullException("message");

            }

            if (p_caption == null)

            {

                throw new ArgumentNullException("caption");

            }

            if (p_owner == null && Application.Current != null) p_owner = Application.Current.MainWindow;

            String l_message = GetDetailMessage(p_exception);

            IExceptionMessageBoxView view = new T();

            view.Model = new ExceptionMessageBoxViewModel()

            {

                Caption = p_caption,

                UserMessage = p_message,

                ExceptionDetail = l_message,

                MessageBoxButton = p_button

            };

            return view.ShowExceptionMessage(p_owner);

e quindi viene chiamata la funzione per visualizzare la finestra di errore:

        public MessageBoxResult ShowExceptionMessage(Window owner)

        {

            Owner = owner;

            this.m_MessageBoxResult = MessageBoxResult.None;

            this.ShowDialog();

            return this.m_MessageBoxResult;

        }

Segue il codice di gestione dei 4 pulsanti:

        private void okButton_Click(object sender, RoutedEventArgs e)

        {

            this.m_MessageBoxResult = MessageBoxResult.OK;

            this.DialogResult = true;

        }

        private void yesButton_Click(object sender, RoutedEventArgs e)

        {

            this.m_MessageBoxResult = MessageBoxResult.Yes;

            this.DialogResult = true;

        }

        private void noButton_Click(object sender, RoutedEventArgs e)

        {

            this.m_MessageBoxResult = MessageBoxResult.No;

            this.DialogResult = false;

        }

        private void cancelButton_Click(object sender, RoutedEventArgs e)

        {

            this.m_MessageBoxResult = MessageBoxResult.Cancel;

            this.DialogResult = false;

        }

Vediamo ora come personalizzare la finestra. Con questo codice

ExceptionMessageBox<ExceptionMessageBoxView>.Show("Si è verificata un’eccezione.", ex);

viene visualizzata solo il pulsante OK.

E se avessimo un caso che a seguito dell’errore ci sia un tentativo di riprovare l’operazione, e quindi visualizzare i pulsanti si e no? Nessun problema, basta cambiare la chiamata in questo modo:

                ExceptionMessageBox<ExceptionMessageBoxView>.Show("Operazione non valida. Vuoi riprovare?", ex,"Messaggio di errore",MessageBoxButton.YesNo, Owner);

Ed ecco il risultato:

Personalizzazione

Ovviamente poi con l’XAML ci possiamo sbizzarrire, creando delle finestre colorate e aggiungendo stili e template.

Ad esempio l’avete mai vista una finestra di errore così? Non è graziosa e graficamente accattivante?


Conclusioni

Abbiamo finito il primo articolo su librerie da aggiungere ai vostri progetti che vi faranno fare sicuramente una bella figura senza andare ad intaccare più di tanto prestazioni e memoria. Nel prossimo articolo vedremo un’altra libreria.