Vista web

Un control de vista web inserta una vista en la aplicación que representa al contenido web, mediante el motor de representación de Microsoft Edge (versión anterior). En un control de vista web también pueden aparecer y funcionar hipervínculos.

Importante

El WebView2 control está disponible como parte de la Biblioteca de interfaz de usuario de Windows 3 (WinUI3). WebView2usa Microsoft Edge (Chromium) como motor de representación para mostrar contenido web en aplicaciones. Para obtener más información, consulte Introducción a Microsoft Edge WebView2, Introducción a WebView2 en WinUI 3 (versión preliminar) y WebView2 en la referencia de API de WinUI.

¿Es este el control adecuado?

Usa un control de vista web para mostrar contenido HTML de formato enriquecido desde un servidor web remoto, código generado de forma dinámica o archivos de contenido en tu paquete de la aplicación. El contenido enriquecido también puede contener código de script y establecer la comunicación entre el script y el código de tu aplicación.

Recomendaciones

  • Asegúrate de que el sitio web cargado tiene un formato correcto para el dispositivo y usa colores, tipografía y navegación coherentes con el resto de tu aplicación.
  • Los campos de entrada deben tener el tamaño correcto. Los usuarios podrían no darse cuenta de que pueden acercar la imagen para escribir texto.
  • Si una vista web no se parece al resto de tu aplicación, considera la posibilidad de usar controles alternativos u otras maneras de realizar las tareas pertinentes. Si tu vista web coincide con el resto de la aplicación, los usuarios considerarán el conjunto una experiencia óptima.

Creación de una vista web

Modificación de la apariencia de una vista web

WebView no es una subclase de Control, por lo que no tiene una plantilla de control. Sin embargo, puedes establecer varias propiedades para controlar algunos aspectos visuales de la vista web.

  • Para restringir el área de visualización, establece las propiedades Width y Height.
  • Para traducir, escalar, sesgar y girar una vista web, usa la propiedad RenderTransform.
  • Para controlar la opacidad de la vista web, establece la propiedad Opacity.
  • Para especificar un color que se usa como fondo de la página web cuando el contenido HTML no especifica uno, establece la propiedad DefaultBackgroundColor.

Obtención del título de la página web

Puedes obtener el título del documento HTML que se muestra actualmente en la vista web mediante la propiedad DocumentTitle.

Eventos de entrada y orden de tabulación

Aunque WebView no es una subclase de Control, recibe el foco de entrada del teclado y participa en la secuencia de tabulación. Proporciona un método Focus y eventos GotFocus y LostFocus, pero carece de propiedades relacionadas con la tabulación. Su posición en la secuencia de tabulación es igual a su posición en el orden de documentos XAML. La secuencia de tabulación incluye todos los elementos de la vista web que pueden recibir el foco de entrada.

Tal y como se indica en la tabla Events de la página de la clase WebView, la vista web no admite la mayoría de los eventos de entrada de usuario heredados de UIElement, como KeyDown, KeyUp y PointerPressed. En vez de eso, puedes usar InvokeScriptAsync con la función JavaScript eval para usar los controladores de eventos HTML y usar window.external.notify desde el controlador de eventos HTML para notificar a la aplicación mediante WebView.ScriptNotify.

La vista web proporciona varias API para navegación básica: GoBack, GoForward, Stop, Refresh, CanGoBack y CanGoForward. Puedes usarlas para agregar a tu aplicación funcionalidades de exploración web típicas.

Para establecer el contenido inicial de la vista web, debes establecer la propiedad Source en XAML. El analizador XAML convierte automáticamente la cadena en un URI.

<!-- Source file is on the web. -->
<WebView x:Name="webView1" Source="http://www.contoso.com"/>

<!-- Source file is in local storage. -->
<WebView x:Name="webView2" Source="ms-appdata:///local/intro/welcome.html"/>

<!-- Source file is in the app package. -->
<WebView x:Name="webView3" Source="ms-appx-web:///help/about.html"/>

La propiedad Source se puede establecer en el código, pero es más habitual usar uno de los métodos Navigate para cargar contenido en el código.

Para cargar contenido web, usa el método Navigate con un URI que utilice el esquema http o https.

webView1.Navigate(new Uri("http://www.contoso.com"));

Para navegar a un URI con una solicitud POST y encabezados HTTP, usa el método NavigateWithHttpRequestMessage. Este método solo admite HttpMethod.Post y HttpMethod.Get como valores de la propiedad HttpRequestMessage.Method.

Para cargar contenido sin comprimir y sin cifrar desde los almacenes de datos LocalFolder o TemporaryFolder de la aplicación, usa el método Navigate con un URI que utilice ms-appdata scheme. La compatibilidad de la vista web con este esquema requiere que coloques el contenido en una subcarpeta de la carpeta local o temporal. Esto permite la navegación a identificadores URI como ms-appdata:///local/carpeta/archivo.html y ms-appdata:///temp/carpeta/archivo.html. (Para cargar archivos comprimidos o cifrados, consulta NavigateToLocalStreamUri).

Cada una de estas subcarpetas de primer nivel está aislada del contenido de otras subcarpetas de primer nivel. Por ejemplo, puedes ir a ms-appdata:///temp/carpeta1/archivo.html, pero en este archivo no puedes tener un vínculo a ms-appdata:///temp/carpeta2/archivo.html. Sin embargo, sí puedes establecer un vínculo al contenido HTML del paquete de la aplicación mediante el esquema ms-appx-web, y al contenido web mediante los esquemas URI http y https.

webView1.Navigate(new Uri("ms-appdata:///local/intro/welcome.html"));

Para cargar contenido desde el paquete de la aplicación, usa el método Navigate con un URI que utilice el esquema ms-appx-web.

webView1.Navigate(new Uri("ms-appx-web:///help/about.html"));

Puedes cargar contenido local a través de una resolución personalizada mediante el método NavigateToLocalStreamUri. Esto posibilita escenarios avanzados como la descarga y el almacenamiento en caché de contenido web para usarlo sin conexión, o la extracción de contenido de un archivo comprimido.

Respuesta a eventos de navegación

El control de vista web proporciona varios eventos que puedes usar para responder a estados de carga de contenido y navegación. Los eventos se producen en el siguiente orden para el contenido de vista web raíz: NavigationStarting, ContentLoading, DOMContentLoaded, NavigationCompleted

NavigationStarting: se produce antes de que la vista web se desplace al nuevo contenido. Para cancelar la navegación en un controlador para este evento, establece la propiedad WebViewNavigationStartingEventArgs.Cancel en true.

webView1.NavigationStarting += webView1_NavigationStarting;

private void webView1_NavigationStarting(object sender, WebViewNavigationStartingEventArgs args)
{
    // Cancel navigation if URL is not allowed. (Implementation of IsAllowedUri not shown.)
    if (!IsAllowedUri(args.Uri))
        args.Cancel = true;
}

ContentLoading: se produce cuando la vista web empieza a cargar contenido nuevo.

webView1.ContentLoading += webView1_ContentLoading;

private void webView1_ContentLoading(WebView sender, WebViewContentLoadingEventArgs args)
{
    // Show status.
    if (args.Uri != null)
    {
        statusTextBlock.Text = "Loading content for " + args.Uri.ToString();
    }
}

DOMContentLoaded: se produce cuando la vista web ha terminado de analizar el contenido HTML actual.

webView1.DOMContentLoaded += webView1_DOMContentLoaded;

private void webView1_DOMContentLoaded(WebView sender, WebViewDOMContentLoadedEventArgs args)
{
    // Show status.
    if (args.Uri != null)
    {
        statusTextBlock.Text = "Content for " + args.Uri.ToString() + " has finished loading";
    }
}

NavigationCompleted: se produce cuando la vista web ha terminado de cargar el contenido actual, o si se produce un error de navegación. Para determinar si se produjo un error en la navegación, comprueba las propiedades IsSuccess y WebErrorStatus de la clase WebViewNavigationCompletedEventArgs.

webView1.NavigationCompleted += webView1_NavigationCompleted;

private void webView1_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
{
    if (args.IsSuccess == true)
    {
        statusTextBlock.Text = "Navigation to " + args.Uri.ToString() + " completed successfully.";
    }
    else
    {
        statusTextBlock.Text = "Navigation to: " + args.Uri.ToString() +
                               " failed with error " + args.WebErrorStatus.ToString();
    }
}

Los eventos similares se producen en el mismo orden para cada iframe en el contenido de la vista web:

  • FrameNavigationStarting: se produce antes de que un fotograma en la vista web navegue a nuevo contenido.
  • FrameContentLoading: se produce cuando un fotograma en la vista web empieza a cargar contenido nuevo.
  • FrameDOMContentLoaded: se produce cuando un fotograma en la vista web ha terminado de analizar el contenido HTML actual.
  • FrameNavigationCompleted: se produce cuando un fotograma en la vista web ha terminado de cargar el contenido.

Respuesta a posibles problemas

Puedes responder a posibles problemas con el contenido, como scripts de larga duración, elementos que la vista web no puede cargar y advertencias de contenido no seguro.

Puede parecer que la aplicación no responde mientras se ejecutan scripts. El evento LongRunningScriptDetected se produce periódicamente mientras la vista web ejecuta JavaScript, lo que ofrece una oportunidad para interrumpir el script. Para determinar cuánto tiempo se ha estado ejecutando el script, comprueba la propiedad ExecutionTime de WebViewLongRunningScriptDetectedEventArgs. Para detener el script, establece la propiedad StopPageScriptExecution de los argumentos del evento en true. No se volverá a ejecutar el script detenido a menos que se vuelva a cargar durante una navegación posterior por la vista web.

El control de vista web no puede hospedar tipos de archivo arbitrarios. Cuando se intenta cargar contenido que la vista web no puede hospedar, se produce el evento UnviewableContentIdentified. Puedes controlar este evento y notificar al usuario, o usar la clase Launcher para redirigir el archivo a un explorador externo o a otra aplicación.

Del mismo modo, el evento UnsupportedUriSchemeIdentified se produce cuando se invoca un esquema de URI no compatible en el contenido web, como fbconnect:// o mailto://. Puedes controlar este evento para proporcionar un comportamiento personalizado, en vez de permitir que el iniciador del sistema predeterminado inicie el URI.

El evento UnsafeContentWarningDisplayingevent se produce cuando el filtro SmartScreen indica que un contenido no es seguro y se muestra una página de aviso en la vista web. Si el usuario elige continuar con la navegación, la navegación posterior en esa página no mostrará la advertencia ni activará el evento.

Control de casos especiales del contenido de la vista web

Puedes usar la propiedad ContainsFullScreenElement y el evento ContainsFullScreenElementChanged para detectar el estado de pantalla completa, responder al mismo y habilitar esta experiencia para el contenido web, por ejemplo, para reproducir vídeo de pantalla completa. Por ejemplo, puedes usar el evento ContainsFullScreenElementChanged para cambiar el tamaño de la vista web de modo que ocupe la totalidad de la vista de la aplicación, o bien, como se muestra en el siguiente ejemplo, colocar una aplicación en ventana en modo de pantalla completa cuando quieras esta experiencia web.

// Assume webView is defined in XAML
webView.ContainsFullScreenElementChanged += webView_ContainsFullScreenElementChanged;

private void webView_ContainsFullScreenElementChanged(WebView sender, object args)
{
    var applicationView = ApplicationView.GetForCurrentView();

    if (sender.ContainsFullScreenElement)
    {
        applicationView.TryEnterFullScreenMode();
    }
    else if (applicationView.IsFullScreenMode)
    {
        applicationView.ExitFullScreenMode();
    }
}

Puedes usar el evento NewWindowRequested para controlar los casos en los que el contenido web hospedado solicite que se muestre una nueva ventana, como una ventana emergente. Puedes usar otro control WebView para mostrar el contenido de la ventana solicitada.

Usa el evento PermissionRequested para habilitar características web que requieran funciones especiales. Actualmente, incluyen la geolocalización, el almacenamiento IndexedDB, y el audio y vídeo del usuario (por ejemplo, de un micrófono o una cámara web). Aunque la aplicación tenga acceso a la ubicación o el contenido multimedia del usuario, es necesario declarar esta funcionalidad en el manifiesto de la aplicación. Por ejemplo, una aplicación que usa la geolocalización precisa las siguientes declaraciones de funcionalidades como mínimo en Package.appxmanifest:

  <Capabilities>
    <Capability Name="internetClient" />
    <DeviceCapability Name="location" />
  </Capabilities>

Además de administrar mediante la aplicación el evento PermissionRequested, el usuario debe aprobar los cuadros de diálogo estándar del sistema para que la aplicación solicite las funciones multimedia o de ubicación que se quieren habilitar.

En el siguiente ejemplo, una aplicación permite la geolocalización en un mapa de Bing:

// Assume webView is defined in XAML
webView.PermissionRequested += webView_PermissionRequested;

private void webView_PermissionRequested(WebView sender, WebViewPermissionRequestedEventArgs args)
{
    if (args.PermissionRequest.PermissionType == WebViewPermissionType.Geolocation &&
        args.PermissionRequest.Uri.Host == "www.bing.com")
    {
        args.PermissionRequest.Allow();
    }
}

Si la aplicación requiere la entrada del usuario u otras operaciones asincrónicas para responder a una solicitud de permiso, usa el método Defer de WebViewPermissionRequest para crear un elemento WebViewDeferredPermissionRequest sobre el que se pueda actuar más adelante. Consulta WebViewPermissionRequest.Defer.

Si los usuarios deben cerrar sesión de forma segura en un sitio web hospedado en una vista web, o en otros casos en los que la seguridad sea importante, llama al método estático ClearTemporaryWebDataAsync para borrar todo el contenido de una sesión de vista web almacenado localmente en caché. Esto impide que usuarios malintencionados obtengan acceso a información confidencial.

Interacción con el contenido de la vista web

Puedes interactuar con el contenido de la vista web usando el método InvokeScriptAsync para invocar o insertar script en dicho contenido, y el evento ScriptNotify para obtener información de este.

Para invocar JavaScript dentro del contenido de la vista web, usa el método InvokeScriptAsync. El script invocado solo puede devolver valores de cadena.

Por ejemplo, si el contenido una vista web llamada webView1 contiene una función llamada setDate que utiliza 3 parámetros, puedes invocarla de la manera siguiente.

string[] args = {"January", "1", "2000"};
string returnValue = await webView1.InvokeScriptAsync("setDate", args);

Puedes usar InvokeScriptAsync con la función eval de JavaScript para insertar contenido en la página web.

Aquí, el texto de un cuadro de texto XAML (nameTextBox.Text) se escribe en un elemento div en una página HTML hospedada en webView1.

private async void Button_Click(object sender, RoutedEventArgs e)
{
    string functionString = String.Format("document.getElementById('nameDiv').innerText = 'Hello, {0}';", nameTextBox.Text);
    await webView1.InvokeScriptAsync("eval", new string[] { functionString });
}

Los scripts del contenido de la vista web pueden usar window.external.notify con un parámetro de cadena para enviar información a la aplicación. Para recibir estos mensajes, controla el evento ScriptNotify.

Para permitir que una página web externa active el evento ScriptNotify al llamar a window.external.notify, debes incluir el URI de la página en la sección ApplicationContentUriRules del manifiesto de la aplicación. (Puedes hacerlo en Microsoft Visual Studio en la pestaña URI de contenido del diseñador Package.appxmanifest). Los URI en esta lista deben usar HTTPS y pueden contener caracteres comodín en el subdominio (por ejemplo, https://*.microsoft.com), pero no en el dominio (por ejemplo, https://*.com y https://*.*). El requisito del manifiesto no se aplica al contenido que se origina en el paquete de la aplicación, que usa un URI ms-local-stream:// o se carga mediante NavigateToString.

Acceso a Windows Runtime en una vista web

Puedes usar el método AddWebAllowedObject para insertar una instancia de una clase nativa de un componente de Windows Runtime en el contexto JavaScript de la vista web. Así dispondrás de acceso completo a los métodos, propiedades y eventos nativos del objeto en el contenido JavaScript de la vista web. La clase se debe representar con el atributo AllowForWeb.

Por ejemplo, este código inserta en una vista web una instancia de MyClass importada de un componente de Windows Runtime.

private void webView_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args)
{
    if (args.Uri.Host == "www.contoso.com")
    {
        webView.AddWebAllowedObject("nativeObject", new MyClass());
    }
}

Para obtener más información, consulta WebView.AddWebAllowedObject.

Además, puedes permitir que el contenido JavaScript confiable de una vista web acceda directamente a las API de Windows Runtime. Esto proporciona funcionalidades nativas de alta eficacia para aplicaciones web hospedadas en una vista web. Para habilitar esta característica, el URI del contenido confiable debe estar en la lista de permitidos de las ApplicationContentUriRules de la aplicación en Package.appxmanifest, y WindowsRuntimeAccess debe estar establecido específicamente en "all".

Este ejemplo muestra una sección del manifiesto de la aplicación. Aquí, un URI local obtiene acceso a Windows Runtime.

  <Applications>
    <Application Id="App"
      ...

      <uap:ApplicationContentUriRules>
        <uap:Rule Match="ms-appx-web:///Web/App.html" WindowsRuntimeAccess="all" Type="include"/>
      </uap:ApplicationContentUriRules>
    </Application>
  </Applications>

Opciones de hospedaje de contenido web

Puedes usar la propiedad WebView.Settings (del tipo WebViewSettings) para controlar si JavaScript e IndexedDB están habilitados. Por ejemplo, si usas una vista web para mostrar contenido estrictamente estático, puedes deshabilitar JavaScript para obtener el mejor rendimiento.

Captura de contenido de una vista web

Para habilitar el uso compartido del contenido de una vista web con otras aplicaciones, usa el método CaptureSelectedContentToDataPackageAsync, que devuelve el contenido seleccionado como DataPackage. Este método es asincrónico, por lo que debes usar un aplazamiento para evitar que el controlador de evento DataRequested actúe antes de que finalice la llamada asincrónica.

Para obtener una imagen previa del contenido actual de la vista web, usa el método CapturePreviewToStreamAsync. Este método crea una imagen del contenido actual y la escribe en la secuencia especificada.

Comportamiento de subprocesos

De manera predeterminada, el contenido de una vista web se hospeda en el subproceso de la interfaz de usuario en la familia de dispositivos de escritorio, y fuera de dicho subproceso en todos los demás dispositivos. Puedes usar la propiedad estática WebView.DefaultExecutionMode para consultar el comportamiento del subproceso predeterminado para el cliente actual. Si es necesario, puedes usar el constructor WebView(WebViewExecutionMode) para invalidar este comportamiento.

Nota Puede haber problemas de rendimiento al hospedar contenido en el subproceso de interfaz de usuario en dispositivos móviles, por lo que asegúrese de probar en todos los dispositivos de destino al cambiar DefaultExecutionMode.

Una vista web que hospeda contenido en el subproceso de la interfaz de usuario no es compatible con los controles primarios que requieren gestos para propagar desde el control de vista web al elemento primario, como FlipView, ScrollViewer y otros controles relacionados. Estos controles no podrán recibir los gestos que se inicien en la vista web fuera del subproceso. Además, no se admite directamente la impresión de contenido web desde subprocesos. Deberás imprimir los elementos con un relleno WebViewBrush.

Obtención del código de ejemplo