Información general sobre cuadros de diálogo

Normalmente, las aplicaciones independientes tienen una ventana principal que muestra los datos principales con los que funciona la aplicación y expone la función para procesar esos datos mediante mecanismos de interfaz de usuario como barras de menús, barras de herramientas y barras de estado. Una aplicación no trivial también puede mostrar ventanas adicionales para realizar lo siguiente:

  • Mostrar información específica a los usuarios.

  • Recopilar información de los usuarios.

  • Mostrar y recopilar información.

Estos tipos de ventanas se conocen como cuadros de diálogo, y hay dos tipos: modales y no modales.

Un cuadro de diálogo modal se muestra mediante una función cuando esta necesita datos adicionales de un usuario para continuar. Como la función depende del cuadro de diálogo modal para recopilar datos, el cuadro de diálogo modal también impide que un usuario active otras ventanas de la aplicación mientras permanece abierto. En la mayoría de los casos, un cuadro de diálogo modal permite que un usuario indique cuando ha terminado con el cuadro de diálogo modal presionando un botón Aceptar o Cancelar. Al presionar el botón Aceptar se indica que el usuario ha especificado los datos y quiere que la función continúe procesando esos datos. Al presionar el botón Cancelar se indica que un usuario quiere detener la ejecución de la función por completo. Los ejemplos más comunes de cuadros de diálogo modales se muestran para abrir, guardar e imprimir datos.

Por otro lado, un cuadro de diálogo no modal no impide que un usuario active otras ventanas mientras está abierto. Por ejemplo, si un usuario quiere buscar las repeticiones de una palabra determinada en un documento, a menudo una ventana principal abrirá un cuadro de diálogo para solicitar al usuario la palabra que está buscando. En cambio, como buscar una palabra no impide que un usuario edite el documento, el cuadro de diálogo no necesita ser modal. Un cuadro de diálogo no modal proporciona al menos un botón Cerrar para cerrar el cuadro de diálogo, y puede proporcionar botones adicionales para ejecutar funciones específicas, como un botón Buscar siguiente para buscar la siguiente palabra que coincide con los criterios de búsqueda de una búsqueda de palabras.

Windows Presentation Foundation (WPF) le permite crear varios tipos de cuadros de diálogo, incluidos cuadros de mensaje, cuadros de diálogo comunes y cuadros de diálogo personalizados. En este tema se trata cada uno, y el Ejemplo de cuadro de diálogo proporciona ejemplos relacionados.

Cuadros de mensaje

Un cuadro de mensaje es un cuadro de diálogo que puede usarse para mostrar información de texto y para permitir que los usuarios tomen decisiones con los botones. En la siguiente figura se muestra un cuadro de mensaje que muestra información de texto, realiza una pregunta y proporciona tres botones al usuario para responderla.

Cuadro de diálogo Procesador de texto que pregunta si desea guardar los cambios en el documento antes de que se cierre la aplicación.

Para crear un cuadro de mensaje, use la clase MessageBox. MessageBox le permite configurar los botones, el icono, el título y el texto del cuadro de mensaje mediante código, como el que se muestra a continuación.

// Configure the message box to be displayed
string messageBoxText = "Do you want to save changes?";
string caption = "Word Processor";
MessageBoxButton button = MessageBoxButton.YesNoCancel;
MessageBoxImage icon = MessageBoxImage.Warning;
' Configure the message box to be displayed
Dim messageBoxText As String = "Do you want to save changes?"
Dim caption As String = "Word Processor"
Dim button As MessageBoxButton = MessageBoxButton.YesNoCancel
Dim icon As MessageBoxImage = MessageBoxImage.Warning

Para mostrar un cuadro de mensaje, llame al método staticShow como se muestra en el siguiente código.

// Display message box
MessageBox.Show(messageBoxText, caption, button, icon);
' Display message box
MessageBox.Show(messageBoxText, caption, button, icon)

Cuando el código que muestra un cuadro de mensaje necesita detectar y procesar la decisión del usuario (qué botón se ha presionado), el código puede inspeccionar el resultado del cuadro de mensaje, como se muestra en el código siguiente.

// Display message box
MessageBoxResult result = MessageBox.Show(messageBoxText, caption, button, icon);

// Process message box results
switch (result)
{
    case MessageBoxResult.Yes:
        // User pressed Yes button
        // ...
        break;
    case MessageBoxResult.No:
        // User pressed No button
        // ...
        break;
    case MessageBoxResult.Cancel:
        // User pressed Cancel button
        // ...
        break;
}
' Display message box
Dim result As MessageBoxResult = MessageBox.Show(messageBoxText, caption, button, icon)

' Process message box results
Select Case result
    Case MessageBoxResult.Yes
        ' User pressed Yes button
        ' ...
    Case MessageBoxResult.No
        ' User pressed No button
        ' ...
    Case MessageBoxResult.Cancel
        ' User pressed Cancel button
        ' ...
End Select

Para obtener más información sobre el uso de cuadros de mensaje, vea MessageBox, Ejemplo de MessageBox y Ejemplo de cuadro de diálogo.

Aunque MessageBox puede ofrecer una experiencia de usuario de cuadro de diálogo sencilla, la ventaja de usar MessageBox es que es el único tipo de ventana que pueden mostrar las aplicaciones que se ejecutan dentro de un espacio aislado de seguridad de confianza parcial (vea Seguridad (WPF)), como aplicaciones de explorador XAML (XBAP).

La mayoría de los cuadros de diálogo muestran y recopilan datos más complejos que el resultado de un cuadro de mensaje, incluidos texto, selección (casillas), selección mutuamente exclusiva (botón de selección) y selección de listas (cuadros de lista, cuadros combinados, cuadros de lista desplegable). Para estos, Windows Presentation Foundation (WPF) proporciona varios cuadros de diálogo comunes y le permite crear sus propios cuadros de diálogo, aunque el uso de cualquiera de ellos está limitado a aplicaciones que se ejecuten con plena confianza.

Cuadros de diálogo comunes

Windows implementa una variedad de cuadros de diálogo reutilizables que son comunes a todas las aplicaciones, incluidos los cuadros de diálogo para abrir y guardar archivos, e imprimir. Como estos cuadros de diálogo se implementan mediante el sistema operativo, pueden compartirse entre todas las aplicaciones que se ejecutan en el sistema operativo, que ayuda a la coherencia de la experiencia de usuario; cuando los usuarios están familiarizados con el uso de un cuadro de diálogo proporcionado por el sistema operativo en una aplicación, no necesitan obtener información sobre cómo usar ese cuadro de diálogo en otras aplicaciones. Dado que estos cuadros de diálogo están disponibles en todas las aplicaciones y como pueden ayudar a proporcionar una experiencia de usuario coherente, se conocen como cuadros de diálogo comunes.

Windows Presentation Foundation (WPF) encapsula los cuadros de diálogo comunes de Abrir archivo, Guardar archivo e Imprimir y los expone como clases administradas para su uso en aplicaciones independientes. En este tema se proporciona una breve introducción de cada uno.

Cuadro de diálogo Abrir archivo

El cuadro de diálogo Abrir archivo, que se muestra en la siguiente figura, se usa por la función de apertura de archivos para recuperar el nombre de un archivo que se va a abrir.

Cuadro de diálogo Abrir que muestra la ubicación para recuperar el archivo.

El cuadro de diálogo común para abrir un archivo se implementa como la clase OpenFileDialog y se encuentra en el espacio de nombres Microsoft.Win32. En el siguiente código se muestra cómo crear, configurar y mostrar uno, y cómo procesar el resultado.

// Configure open file dialog box
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
dlg.FileName = "Document"; // Default file name
dlg.DefaultExt = ".txt"; // Default file extension
dlg.Filter = "Text documents (.txt)|*.txt"; // Filter files by extension

// Show open file dialog box
Nullable<bool> result = dlg.ShowDialog();

// Process open file dialog box results
if (result == true)
{
    // Open document
    string filename = dlg.FileName;
}
' Configure open file dialog box
Dim dlg As New Microsoft.Win32.OpenFileDialog()
dlg.FileName = "Document" ' Default file name
dlg.DefaultExt = ".txt" ' Default file extension
dlg.Filter = "Text documents (.txt)|*.txt" ' Filter files by extension

' Show open file dialog box
Dim result? As Boolean = dlg.ShowDialog()

' Process open file dialog box results
If result = True Then
    ' Open document
    Dim filename As String = dlg.FileName
End If

Para obtener más información sobre el cuadro de diálogo Abrir archivo, vea Microsoft.Win32.OpenFileDialog.

Nota

OpenFileDialog puede usarse para recuperar nombres de archivo de manera segura mediante aplicaciones que se ejecuten con confianza parcial (vea Seguridad (WPF)).

Guardar archivo (cuadro de diálogo)

El cuadro de diálogo Guardar archivo, que se muestra en la siguiente figura, se usa por la función de guardado de archivos para recuperar el nombre de un archivo que se va a guardar.

Cuadro de diálogo Guardar como en el que se muestra la ubicación para guardar el archivo.

El cuadro de diálogo común para guardar archivos se implementa como la clase SaveFileDialog y se encuentra en el espacio de nombres Microsoft.Win32. En el siguiente código se muestra cómo crear, configurar y mostrar uno, y cómo procesar el resultado.

// Configure save file dialog box
Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
dlg.FileName = "Document"; // Default file name
dlg.DefaultExt = ".txt"; // Default file extension
dlg.Filter = "Text documents (.txt)|*.txt"; // Filter files by extension

// Show save file dialog box
Nullable<bool> result = dlg.ShowDialog();

// Process save file dialog box results
if (result == true)
{
    // Save document
    string filename = dlg.FileName;
}
' Configure save file dialog box
Dim dlg As New Microsoft.Win32.SaveFileDialog()
dlg.FileName = "Document" ' Default file name
dlg.DefaultExt = ".txt" ' Default file extension
dlg.Filter = "Text documents (.txt)|*.txt" ' Filter files by extension

' Show save file dialog box
Dim result? As Boolean = dlg.ShowDialog()

' Process save file dialog box results
If result = True Then
    ' Save document
    Dim filename As String = dlg.FileName
End If

Para obtener más información sobre el cuadro de diálogo Guardar archivo, vea Microsoft.Win32.SaveFileDialog.

El cuadro de diálogo Imprimir, que se muestra en la siguiente figura, se usa por la función de impresión para elegir y configurar la impresora con la que el usuario quiere imprimir los datos.

Captura de pantalla que muestra un cuadro de diálogo Imprimir.

El cuadro de diálogo común de impresión se implementa como la clase PrintDialog y se encuentra en el espacio de nombres System.Windows.Controls. En el siguiente código se muestra cómo crear, configurar y mostrar uno.

// Configure printer dialog box
System.Windows.Controls.PrintDialog dlg = new System.Windows.Controls.PrintDialog();
dlg.PageRangeSelection = PageRangeSelection.AllPages;
dlg.UserPageRangeEnabled = true;

// Show save file dialog box
Nullable<bool> result = dlg.ShowDialog();

// Process save file dialog box results
if (result == true)
{
    // Print document
}
' Configure printer dialog box
Dim dlg As New PrintDialog()
dlg.PageRangeSelection = PageRangeSelection.AllPages
dlg.UserPageRangeEnabled = True

' Show save file dialog box
Dim result? As Boolean = dlg.ShowDialog()

' Process save file dialog box results
If result = True Then
    ' Print document
End If

Para obtener más información sobre el cuadro de diálogo de impresión, vea System.Windows.Controls.PrintDialog. Para obtener información detallada sobre la impresión en WPF vea Información general sobre impresión.

Cuadros de diálogo personalizados

Aunque los cuadros de diálogo comunes son útiles, y deben usarse cuando sea posible, no admiten los requisitos de los cuadros de diálogo específicos de dominio. En estos casos, necesita crear sus propios cuadros de diálogo. Como veremos, un cuadro de diálogo es una ventana con comportamientos especiales. Window implementa esos comportamientos y, por consiguiente, usa Window para crear cuadros de diálogo modales y no modales personalizados.

Creación de un cuadro de diálogo modal personalizado

En este tema se muestra cómo usar Window para crear una implementación de cuadro de diálogo modal típica, con el cuadro de diálogo Margins como ejemplo (vea Ejemplo de cuadro de diálogo). El cuadro de diálogo Margins se muestra en la figura siguiente.

Cuadro de diálogo Márgenes con campos para definir los márgenes izquierdo, superior, derecho e inferior.

Configuración de un cuadro de diálogo modal

La interfaz de usuario de un cuadro de diálogo típico incluye lo siguiente:

  • Los distintos controles que se necesitan para recopilar los datos deseados.

  • Un botón Aceptar en el que los usuarios hacen clic para cerrar el cuadro de diálogo, devolver la función y continuar el procesamiento.

  • Un botón Cancelar en el que los usuarios hacen clic para cerrar el cuadro de diálogo y detener la función del procesamiento.

  • Un botón Cerrar en la barra de título.

  • Un icono.

  • Botones Minimizar, Maximizar y Restaurar.

  • Un menú Sistema para minimizar, maximizar, restaurar y cerrar el cuadro de diálogo.

  • Un posición encima y en el centro de la ventana que ha abierto el cuadro de diálogo.

  • La capacidad de ser redimensionables donde sea posible, para evitar que el cuadro de diálogo sea demasiado pequeño y para proporcionar al usuario un tamaño predeterminado útil. Para ello, necesita establecer las dimensiones mínimas y predeterminadas respectivamente.

  • La tecla ESC como un método abreviado de teclado que provoque que el botón Cancelar se presione. Para ello, establezca la propiedad IsCancel del botón Cancelar en true.

  • La tecla ENTRAR (o RETORNO) como un método abreviado de teclado que provoque que el botón Aceptar se presione. Para ello, establezca la propiedad IsDefault del botón ENTRAR en true.

El siguiente código muestra esta configuración.

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.MarginsDialogBox"
    xmlns:local="clr-namespace:SDKSample"
    Title="Margins"
    Height="190"
    Width="300"
    MinHeight="10"
    MinWidth="300"
    ResizeMode="CanResizeWithGrip"
    ShowInTaskbar="False"
    WindowStartupLocation="CenterOwner" 
    FocusManager.FocusedElement="{Binding ElementName=leftMarginTextBox}">

  <Grid>
    <!-- Accept or Cancel -->
    <StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="4">
      <Button Name="okButton" Click="okButton_Click" IsDefault="True">OK</Button>
      <Button Name="cancelButton" IsCancel="True">Cancel</Button>
    </StackPanel>
  </Grid >
</Window>
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace SDKSample
{
    public partial class MarginsDialogBox : Window
    {
        public MarginsDialogBox()
        {
            InitializeComponent();
        }
    }
}
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Input

Namespace SDKSample
    Public Class MarginsDialogBox
        Inherits Window

        Public Sub New()
            Me.InitializeComponent()
        End Sub
    End Class
End Namespace

La experiencia de usuario de un cuadro de diálogo también se extiende a la barra de menús de la ventana que abre el cuadro de diálogo. Cuando un elemento de menú ejecuta una función que requiere interacción del usuario mediante un cuadro de diálogo antes de que la función pueda continuar, el elemento de menú de la función tendrá puntos suspensivos en su encabezado, como se muestra aquí.

<!--Main Window-->
<MenuItem Name="formatMarginsMenuItem" Header="_Margins..." Click="formatMarginsMenuItem_Click" />

Cuando un elemento de menú ejecuta una función que muestra un cuadro de diálogo que no necesita interacción del usuario, como un cuadro de diálogo Acerca de, no se necesitan los puntos suspensivos.

Apertura de un cuadro de diálogo modal

Un cuadro de diálogo se muestra normalmente como el resultado de un usuario que selecciona un elemento de menú para realizar una función específica de dominio, como establecer los márgenes de un documento en un procesador de textos. Mostrar una ventana como un cuadro de diálogo es similar a mostrar una ventana normal, aunque necesita una configuración específica de cuadro de diálogo adicional. El proceso completo de crear instancias, configurar y abrir un cuadro de diálogo se muestra en el código siguiente.

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Win32;

namespace SDKSample
{
    public partial class MainWindow : Window
    {
        bool needsToBeSaved;
        void formatMarginsMenuItem_Click(object sender, RoutedEventArgs e)
        {
            // Instantiate the dialog box
            MarginsDialogBox dlg = new MarginsDialogBox();

            // Configure the dialog box
            dlg.Owner = this;
            dlg.DocumentMargin = this.documentTextBox.Margin;

            // Open the dialog box modally
            dlg.ShowDialog();
        }
    }
}
Imports System.ComponentModel
Imports System.Windows
Imports System.Windows.Controls
Imports Microsoft.Win32

Namespace SDKSample
    Public Class MainWindow
        Inherits Window
        
        Private Sub formatMarginsMenuItem_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            ' Instantiate the dialog box
            Dim dlg As New MarginsDialogBox

            ' Configure the dialog box
            dlg.Owner = Me
            dlg.DocumentMargin = Me.documentTextBox.Margin

            ' Open the dialog box modally 
            dlg.ShowDialog()
        End Sub
    End Class
End Namespace

Aquí, el código pasa información predeterminada (los márgenes actuales) al cuadro de diálogo. También establece la propiedad Window.Owner con una referencia a la ventana que está mostrando el cuadro de diálogo. En general, siempre debe establecer el propietario de un cuadro de diálogo para proporcionar comportamientos relacionados con el estado de la ventana que son comunes a todos los cuadros de diálogo (vea Información general sobre ventanas de WPF para obtener más información).

Nota

Debe proporcionar un propietario para admitir la automatización de interfaz de usuario para los cuadros de diálogo (vea UI Automation Overview [Información general de la automatización de la interfaz de usuario]).

Después de que el cuadro de diálogo esté configurado, se muestra modalmente llamando al método ShowDialog.

Validación de los datos proporcionados por el usuario

Cuando un cuadro de diálogo se abre y el usuario proporciona los datos necesarios, un cuadro de diálogo es responsable de garantizar que los datos proporcionados sean válidos por los motivos siguientes:

  • Desde una perspectiva de seguridad, se deben validar todas las entradas.

  • Desde una perspectiva específica de dominio, la validación de datos impide que los datos incorrectos se procesen por el código, que puede provocar excepciones potencialmente.

  • Desde una perspectiva de experiencia de usuario, un cuadro de diálogo puede ayudar a los usuarios a mostrarles qué datos de los que han especificado no son válidos.

  • Desde una perspectiva de rendimiento, la validación de datos en una aplicación de varios niveles puede reducir el número de recorridos de ida y vuelta entre los niveles de aplicación y cliente, especialmente cuando la aplicación está formada por servicios Web o bases de datos basadas en servidor.

Para validar un control enlazado en WPF, necesita definir una regla de validación y asociarla con el enlace. Una regla de validación es una clase personalizada que deriva de ValidationRule. En el siguiente ejemplo se muestra una regla de validación, MarginValidationRule, que comprueba que un valor enlazado es un Double y se encuentra dentro de un intervalo especificado.

using System.Globalization;
using System.Windows.Controls;

namespace SDKSample
{
    public class MarginValidationRule : ValidationRule
    {
        double minMargin;
        double maxMargin;

        public double MinMargin
        {
            get { return this.minMargin; }
            set { this.minMargin = value; }
        }

        public double MaxMargin
        {
            get { return this.maxMargin; }
            set { this.maxMargin = value; }
        }

        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            double margin;

            // Is a number?
            if (!double.TryParse((string)value, out margin))
            {
                return new ValidationResult(false, "Not a number.");
            }

            // Is in range?
            if ((margin < this.minMargin) || (margin > this.maxMargin))
            {
                string msg = string.Format("Margin must be between {0} and {1}.", this.minMargin, this.maxMargin);
                return new ValidationResult(false, msg);
            }

            // Number is valid
            return new ValidationResult(true, null);
        }
    }
}
Imports System.Globalization
Imports System.Windows.Controls

Namespace SDKSample
    Public Class MarginValidationRule
        Inherits ValidationRule

        Private _maxMargin As Double
        Private _minMargin As Double

        Public Property MaxMargin() As Double
            Get
                Return Me._maxMargin
            End Get
            Set(ByVal value As Double)
                Me._maxMargin = value
            End Set
        End Property

        Public Property MinMargin() As Double
            Get
                Return Me._minMargin
            End Get
            Set(ByVal value As Double)
                Me._minMargin = value
            End Set
        End Property

        Public Overrides Function Validate(ByVal value As Object, ByVal cultureInfo As CultureInfo) As ValidationResult
            Dim margin As Double

            ' Is a number?
            If Not Double.TryParse(CStr(value), margin) Then
                Return New ValidationResult(False, "Not a number.")
            End If

            ' Is in range?
            If ((margin < Me.MinMargin) OrElse (margin > Me.MaxMargin)) Then
                Dim msg As String = String.Format("Margin must be between {0} and {1}.", Me.MinMargin, Me.MaxMargin)
                Return New ValidationResult(False, msg)
            End If

            ' Number is valid
            Return New ValidationResult(True, Nothing)
        End Function
    End Class
End Namespace

En este código, la lógica de validación de una regla de validación se implementa mediante la invalidación del método Validate, que valida los datos y devuelve un ValidationResult apropiado.

Para asociar la regla de validación con el control enlazado, use el siguiente marcado.

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.MarginsDialogBox"
    xmlns:local="clr-namespace:SDKSample"
    Title="Margins"
    Height="190"
    Width="300"
    MinHeight="10"
    MinWidth="300"
    ResizeMode="CanResizeWithGrip"
    ShowInTaskbar="False"
    WindowStartupLocation="CenterOwner" 
    FocusManager.FocusedElement="{Binding ElementName=leftMarginTextBox}">

  <Grid>

    <!-- Left Margin -->
    <Label Grid.Column="0" Grid.Row="0">Left Margin:</Label>
    <TextBox Name="leftMarginTextBox" Grid.Column="1" Grid.Row="0">
      <TextBox.Text>
        <Binding Path="Left" UpdateSourceTrigger="PropertyChanged">
          <Binding.ValidationRules>
            <local:MarginValidationRule MinMargin="0" MaxMargin="10" />
          </Binding.ValidationRules>
        </Binding>
      </TextBox.Text>
    </TextBox>
  </Grid >
</Window>

Una vez la regla de validación esté asociada, WPF la aplicará automáticamente cuando los datos se especifiquen en el control enlazado. Cuando un control contiene datos no válidos, WPF mostrará un borde rojo alrededor del control no válido, como se muestra en la siguiente figura.

Cuadro de diálogo Márgenes con un borde rojo alrededor del valor no válido para el margen izquierdo.

WPF no restringe un usuario al control no válido hasta que haya especificado los datos válidos. Este es un buen comportamiento para un cuadro de diálogo; un usuario debe poder navegar libremente por los controles de un cuadro de diálogo sean los datos válidos o no. En cambio, esto significa que un usuario puede especificar datos no válidos y presionar el botón Aceptar. Por este motivo, su código también necesita validar todos los controles de un cuadro de diálogo cuando el botón Aceptar está presionado controlando el evento Click.

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace SDKSample
{
    public partial class MarginsDialogBox : Window
    {
        void okButton_Click(object sender, RoutedEventArgs e)
        {
            // Don't accept the dialog box if there is invalid data
            if (!IsValid(this)) return;
        }

        // Validate all dependency objects in a window
        bool IsValid(DependencyObject node)
        {
            // Check if dependency object was passed
            if (node != null)
            {
                // Check if dependency object is valid.
                // NOTE: Validation.GetHasError works for controls that have validation rules attached
                bool isValid = !Validation.GetHasError(node);
                if (!isValid)
                {
                    // If the dependency object is invalid, and it can receive the focus,
                    // set the focus
                    if (node is IInputElement) Keyboard.Focus((IInputElement)node);
                    return false;
                }
            }

            // If this dependency object is valid, check all child dependency objects
            foreach (object subnode in LogicalTreeHelper.GetChildren(node))
            {
                if (subnode is DependencyObject)
                {
                    // If a child dependency object is invalid, return false immediately,
                    // otherwise keep checking
                    if (IsValid((DependencyObject)subnode) == false) return false;
                }
            }

            // All dependency objects are valid
            return true;
        }
    }
}
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Input

Namespace SDKSample
    Public Class MarginsDialogBox
        Inherits Window

        Private Sub okButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            ' Don't accept the dialog box if there is invalid data
            If Not Me.IsValid(Me) Then Return
        End Sub

        ' Validate all dependency objects in a window
        Private Function IsValid(ByVal node As DependencyObject) As Boolean
            ' Check if dependency object was passed and if dependency object is valid.
            ' NOTE: Validation.GetHasError works for controls that have validation rules attached 
            If ((Not node Is Nothing) AndAlso Validation.GetHasError(node)) Then
                ' If the dependency object is invalid, and it can receive the focus,
                ' set the focus
                If TypeOf node Is IInputElement Then
                    Keyboard.Focus(DirectCast(node, IInputElement))
                End If
                Return False
            End If

            ' If this dependency object is valid, check all child dependency objects
            Dim subnode As Object
            For Each subnode In LogicalTreeHelper.GetChildren(node)
                If (TypeOf subnode Is DependencyObject AndAlso Not Me.IsValid(DirectCast(subnode, DependencyObject))) Then
                    ' If a child dependency object is invalid, return false immediately,
                    ' otherwise keep checking
                    Return False
                End If
            Next

            ' All dependency objects are valid
            Return True
        End Function
    End Class
End Namespace

Este código enumera todos los objetos de dependencia en una ventana y, si alguno no es válido (si GetHasError lo devuelve), el control no válido obtiene el foco, el método IsValid devuelve false y la ventana se considera no válida.

Una vez que un cuadro de diálogo es válido, puede cerrarse y devolverse de manera segura. Como parte del proceso de retorno, necesita devolver un resultado a la función de llamada.

Establecimiento del resultado del cuadro de diálogo modal

Abrir un cuadro de diálogo con ShowDialog es prácticamente como llamar a un método: el código que ha abierto el cuadro de diálogo con ShowDialog espera hasta que se devuelve ShowDialog. Cuando se devuelve ShowDialog, el código que ha realizado la llamada necesita decidir si seguir el procesamiento o detenerlo, en función de si el usuario ha presionado el botón Aceptar o el botón Cancelar. Para facilitar la decisión, el cuadro de diálogo necesita devolver la elección del usuario como un valor Boolean que se devuelve del método ShowDialog.

Cuando se hace clic en el botón Aceptar, ShowDialog debe devolver true. Esto se consigue estableciendo la propiedad DialogResult del cuadro de diálogo cuando se hace clic en el botón Aceptar.

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace SDKSample
{
    public partial class MarginsDialogBox : Window
    {

        void okButton_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = true;
        }
    }
}
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Input

Namespace SDKSample
    Public Class MarginsDialogBox
        Inherits Window

        Private Sub okButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            ' Dialog box accepted
            MyBase.DialogResult = New Nullable(Of Boolean)(True)
        End Sub
    End Class
End Namespace

Tenga en cuenta que establecer la propiedad DialogResult también hace que la ventana se cierre automáticamente, lo que reduce la necesidad de llamar explícitamente a Close.

Cuando se hace clic en el botón Cancelar, ShowDialog debe devolver false, que también necesita establecer la propiedad DialogResult.

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace SDKSample
{
    public partial class MarginsDialogBox : Window
    {

        void cancelButton_Click(object sender, RoutedEventArgs e)
        {
            // Dialog box canceled
            this.DialogResult = false;
        }
    }
}
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Input

Namespace SDKSample
    Public Class MarginsDialogBox
        Inherits Window

        Private Sub cancelButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            ' Dialog box canceled
            Me.DialogResult = False
        End Sub
    End Class
End Namespace

Cuando se establece la propiedad IsCancel de un botón en true y el usuario presiona el botón Cancelar o la tecla ESC, DialogResult se establece automáticamente en false. El siguiente marcado tiene el mismo efecto que el código anterior, sin la necesidad de controlar el evento Click.

<Button Name="cancelButton" IsCancel="True">Cancel</Button>

Un cuadro de diálogo devuelve automáticamente false cuando un usuario presiona el botón Cerrar en la barra de título o selecciona el elemento de menú Cerrar desde el menú Sistema.

Procesamiento de los datos devueltos de un cuadro de diálogo modal

Cuando DialogResult se establece mediante un cuadro de diálogo, la función que lo ha abierto puede obtener el resultado del cuadro de diálogo inspeccionando la propiedad DialogResult cuando se devuelve ShowDialog.

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Win32;

namespace SDKSample
{
    public partial class MainWindow : Window
    {

        void formatMarginsMenuItem_Click(object sender, RoutedEventArgs e)
        {

            // Process data entered by user if dialog box is accepted
            if (dlg.DialogResult == true)
            {
                // Update fonts
                this.documentTextBox.Margin = dlg.DocumentMargin;
            }
        }
    }
}
Imports System.ComponentModel
Imports System.Windows
Imports System.Windows.Controls
Imports Microsoft.Win32

Namespace SDKSample
    Public Class MainWindow
        Inherits Window
        
        Private Sub formatMarginsMenuItem_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            ' Process data entered by user if dialog box is accepted
            If (dlg.DialogResult.GetValueOrDefault = True) Then
                Me.documentTextBox.Margin = dlg.DocumentMargin
            End If
        End Sub
    End Class
End Namespace

Si el resultado del cuadro de diálogo es true, la función lo usa como una indicación para recuperar y procesar los datos proporcionados por el usuario.

Nota

Después de que se haya devuelto ShowDialog, no puede volver a abrirse un cuadro de diálogo. En su lugar, necesita crear una instancia nueva.

Si el resultado del cuadro de diálogo es false, la función debe finalizar el procesamiento correctamente.

Creación de un cuadro de diálogo no modal personalizado

Un cuadro de diálogo no modal, como el cuadro de diálogo Buscar que se muestra en la figura siguiente, tiene el mismo aspecto fundamental que el cuadro de diálogo modal.

Captura de pantalla que muestra un cuadro de diálogo Buscar.

En cambio, el comportamiento es un poco diferente, como se describe en las secciones siguientes.

Apertura de un cuadro de diálogo no modal

Un cuadro de diálogo no modal se abre llamando al método Show.

<!--Main Window-->
<MenuItem Name="editFindMenuItem" Header="_Find" InputGestureText="Ctrl+F" Click="editFindMenuItem_Click" />
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Win32;

namespace SDKSample
{
    public partial class MainWindow : Window
    {
        void editFindMenuItem_Click(object sender, RoutedEventArgs e)
        {
            // Instantiate the dialog box
            FindDialogBox dlg = new FindDialogBox(this.documentTextBox);

            // Configure the dialog box
            dlg.Owner = this;
            dlg.TextFound += new TextFoundEventHandler(dlg_TextFound);

            // Open the dialog box modally
            dlg.Show();
        }
    }
}
Imports System.ComponentModel
Imports System.Windows
Imports System.Windows.Controls
Imports Microsoft.Win32

Namespace SDKSample
    Public Class MainWindow
        Inherits Window
        
        Private Sub editFindMenuItem_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            Dim dlg As New FindDialogBox(Me.documentTextBox)
            dlg.Owner = Me
            AddHandler dlg.TextFound, New TextFoundEventHandler(AddressOf Me.dlg_TextFound)
            dlg.Show()
        End Sub
    End Class
End Namespace

A diferencia de ShowDialog, Show se devuelve inmediatamente. Por consiguiente, la ventana de llamada no puede indicar cuándo se cierra el cuadro de diálogo no modal y, por lo tanto, no sabe cuándo comprobar el resultado de un cuadro de diálogo u obtener los datos de este para un procesamiento posterior. En su lugar, el cuadro de diálogo necesita crear una manera alternativa de devolver los datos a la ventana de llamada para su procesamiento.

Procesamiento de los datos devueltos de un cuadro de diálogo no modal

En este ejemplo, FindDialogBox puede devolver uno o más resultados de búsqueda a la ventana principal, dependiendo del texto que se está buscando sin ninguna frecuencia determinada. Al igual que un cuadro de diálogo modal, un cuadro de diálogo no modal puede devolver resultados mediante propiedades. En cambio, la ventana que tiene el cuadro de diálogo necesita saber cuándo comprobar esas propiedades. Una manera de habilitar esto es que el cuadro de diálogo implemente un evento que se genera cuando se detecta texto. FindDialogBox implementa TextFoundEvent para este fin, que necesita primero un delegado.

using System;

namespace SDKSample
{
    public delegate void TextFoundEventHandler(object sender, EventArgs e);
}
Namespace SDKSample
   Public Delegate Sub TextFoundEventHandler(ByVal sender As Object, ByVal e As EventArgs)
End Namespace

Con el delegado TextFoundEventHandler, FindDialogBox implementa TextFoundEvent.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Text.RegularExpressions;

namespace SDKSample
{
    public partial class FindDialogBox : Window
    {
        public event TextFoundEventHandler TextFound;

        protected virtual void OnTextFound()
        {
            TextFoundEventHandler textFound = this.TextFound;
            if (textFound != null) textFound(this, EventArgs.Empty);
        }

    }
}
Imports System.Windows
Imports System.Windows.Controls
Imports System.Text.RegularExpressions

Namespace SDKSample

    Public Class FindDialogBox
        Inherits Window

        Public Event TextFound As TextFoundEventHandler

        Protected Overridable Sub OnTextFound()
            RaiseEvent TextFound(Me, EventArgs.Empty)
        End Sub

    End Class
End Namespace

Por lo tanto, Find puede generar el evento cuando se detecta un resultado de búsqueda.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Text.RegularExpressions;

namespace SDKSample
{
    public partial class FindDialogBox : Window
    {

        void findNextButton_Click(object sender, RoutedEventArgs e)
        {
                // Text found
                this.index = match.Index;
                this.length = match.Length;
                OnTextFound();
        }
    }
}
Imports System.Windows
Imports System.Windows.Controls
Imports System.Text.RegularExpressions

Namespace SDKSample

    Public Class FindDialogBox
        Inherits Window



            Me.Index = match.Index
            Me.Length = match.Length
            RaiseEvent TextFound(Me, EventArgs.Empty)

    End Class
End Namespace

Después, la ventana propietaria necesita registrar y controlar este evento.

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Win32;

namespace SDKSample
{
    public partial class MainWindow : Window
    {

        void dlg_TextFound(object sender, EventArgs e)
        {
            // Get the find dialog box that raised the event
            FindDialogBox dlg = (FindDialogBox)sender;

            // Get find results and select found text
            this.documentTextBox.Select(dlg.Index, dlg.Length);
            this.documentTextBox.Focus();
        }
    }
}
Imports System.ComponentModel
Imports System.Windows
Imports System.Windows.Controls
Imports Microsoft.Win32

Namespace SDKSample
    Public Class MainWindow
        Inherits Window
        
        Private Sub dlg_TextFound(ByVal sender As Object, ByVal e As EventArgs)
            Dim dlg As FindDialogBox = DirectCast(sender, FindDialogBox)
            Me.documentTextBox.Select(dlg.Index, dlg.Length)
            Me.documentTextBox.Focus()
        End Sub
    End Class
End Namespace

Cierre de un cuadro de diálogo no modal

Como DialogResult no necesita establecerse, un cuadro de diálogo no modal puede cerrarse con mecanismos que proporciona el sistema, incluidos los siguientes:

  • Hacer clic en el botón Cerrar en la barra de título.

  • Presionar ALT+F4.

  • Pulsar Cerrar en el menú Sistema.

De manera alternativa, su código puede llamar a Close cuando se haga clic en el botón Cerrar.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Text.RegularExpressions;

namespace SDKSample
{
    public partial class FindDialogBox : Window
    {

        void closeButton_Click(object sender, RoutedEventArgs e)
        {
            // Close dialog box
            this.Close();
        }
    }
}
Imports System.Windows
Imports System.Windows.Controls
Imports System.Text.RegularExpressions

Namespace SDKSample

    Public Class FindDialogBox
        Inherits Window

        Private Sub closeButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            MyBase.Close()
        End Sub
    End Class
End Namespace

Vea también