Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Si ha diseñado una interfaz de usuario con imágenes de marcador de posición y texto reutilizable, en este tutorial se muestra cómo conectarla a datos reales mediante enlaces de datos. Aprenda a dar formato a los datos, mantener la interfaz de usuario y los datos sincronizados y mejorar la capacidad de mantenimiento del código.
En este tutorial, aprenderás a reemplazar tus plantillas con enlaces de datos y a crear otros vínculos directos entre tu UI y tus datos. También aprenderá a formatear o convertir los datos para mostrarlos y a mantener sincronizada la interfaz de usuario y los datos. Cuando completes este tutorial, puedes mejorar la simplicidad y la organización del código XAML y C#, lo que facilita el mantenimiento y la ampliación.
Comienza con una versión simplificada del ejemplo PhotoLab. Esta versión de inicio incluye la capa de datos completa más los diseños de página XAML básicos y deja fuera muchas características para facilitar el examen del código. Este tutorial no se compila hasta la aplicación completa, así que asegúrese de consultar la versión final para ver características como animaciones personalizadas y diseños adaptables. Puede encontrar la versión final en la carpeta raíz del repositorio windows-appsample-photo-lab.
La aplicación de ejemplo PhotoLab tiene dos páginas. La página principal muestra una vista de galería de fotos, junto con cierta información sobre cada archivo de imagen.
La página de detalles muestra una sola foto después de seleccionarla. Un menú flotante de edición permite alterar, renombrar y guardar la foto.
Prerrequisitos
- Visual Studio 2019 o posterior: Descargar Visual Studio (La edición Community es gratuita).
- Windows SDK (10.0.17763.0 o posterior): descargar la versión más reciente de Windows SDK (gratis)
- Windows 10, versión 1809 o posterior
Parte 0: Obtención del código de inicio de GitHub
Para este tutorial, empezará con una versión simplificada del ejemplo PhotoLab.
Vaya a la página de GitHub del ejemplo: https://github.com/Microsoft/Windows-appsample-photo-lab.
A continuación, debe clonar o descargar el ejemplo. Seleccione el botón para clonar o descargar. Aparece un submenú.
Si no está familiarizado con GitHub:
a) Seleccione Descargar archivo ZIP y guarde el archivo localmente. Esta acción descarga un archivo .zip que contiene todos los archivos de proyecto que necesita.
b. Extraiga el archivo. Use el Explorador de archivos para ir al archivo .zip que acaba de descargar, hacer clic con el botón derecho en él y seleccionar Extraer todo....
c. Navegue hasta su copia local del ejemplo y acceda al directorio
Windows-appsample-photo-lab-master\xaml-basics-starting-points\data-binding.Si está familiarizado con GitHub:
a) Clone la rama principal del repositorio localmente.
b. Vaya al directorio
Windows-appsample-photo-lab\xaml-basics-starting-points\data-binding.Haga doble clic en
Photolab.slnpara abrir la solución en Visual Studio.
Parte 1: Reemplazar los marcadores de posición
En esta sección, creará enlaces únicos en XAML de plantilla de datos para mostrar imágenes reales y metadatos de imagen en lugar de contenido de marcador de posición.
Las vinculaciones de una sola vez son para datos de solo lectura y que no cambian. Son de alto rendimiento y fáciles de crear, por lo que puede mostrar grandes conjuntos de datos en GridView y ListView controles.
Reemplazar los marcadores de posición por vinculaciones únicas
Abra la carpeta
xaml-basics-starting-points\data-bindinge inicie el archivoPhotoLab.slnen Visual Studio.Asegúrese de que la plataforma de soluciones esté configurada en x86 o x64, no en Arm, y a continuación ejecute la aplicación. Este paso muestra el estado de la aplicación con marcadores de posición en la interfaz de usuario, antes de añadir las vinculaciones.
de textoAbra MainPage.xaml y busque un
DataTemplatedenominado ImageGridView_DefaultItemTemplate. Vas a actualizar esta plantilla para usar vínculos de datos.antes:
<DataTemplate x:Key="ImageGridView_DefaultItemTemplate">El
x:Keyusa el valorImageGridViewpara seleccionar esta plantilla para mostrar objetos de datos.Agregue un valor
x:DataTypea la plantilla.después:
<DataTemplate x:Key="ImageGridView_DefaultItemTemplate" x:DataType="local:ImageFileInfo">x:DataTypeindica para qué tipo es esta plantilla. En este caso, es una plantilla para la claseImageFileInfo(dondelocal:indica el espacio de nombres local, tal como se define en una declaración xmlns cerca de la parte superior del archivo).Necesita esto cuando use expresiones de
x:Binden una plantilla de datos, como se describe a continuación.En el
DataTemplate, busque el elementoImagedenominadoItemImagey reemplace su valor deSourcecomo se muestra.antes:
<Image x:Name="ItemImage" Source="/Assets/StoreLogo.png" Stretch="Uniform" />después:
<Image x:Name="ItemImage" Source="{x:Bind ImageSource}" Stretch="Uniform" />x:Nameidentifica un elemento XAML para que puedas hacer referencia a él en otro lugar del XAML y en el código subyacente.expresiones proporcionan un valor a una propiedad de la interfaz de usuario al obtenerlo de la propiedad de un objeto de datos . En las plantillas, la propiedad indicada es una propiedad de aquello en lo que se establece x:DataType. Por lo tanto, en este caso, el origen de datos es la propiedadImageFileInfo.ImageSource.Nota:
El valor de
x:Bindtambién permite al editor conocer el tipo de datos, por lo que puede usar IntelliSense en lugar de escribir el nombre de propiedad en una expresiónx:Bind. Pruébelo en el código que acaba de pegar: coloque el cursor justo después dex:Bindy presione la barra espaciadora para ver una lista de propiedades a las que puede enlazar.Reemplace los valores de los demás controles de interfaz de usuario de la misma manera. (Intente hacerlo con IntelliSense en lugar de copiar o pegar).
antes:
<TextBlock Text="Placeholder" ... /> <StackPanel ... > <TextBlock Text="PNG file" ... /> <TextBlock Text="50 x 50" ... /> </StackPanel> <muxc:RatingControl Value="3" ... />después:
<TextBlock Text="{x:Bind ImageTitle}" ... /> <StackPanel ... > <TextBlock Text="{x:Bind ImageFileType}" ... /> <TextBlock Text="{x:Bind ImageDimensions}" ... /> </StackPanel> <muxc:RatingControl Value="{x:Bind ImageRating}" ... />
Ejecute la aplicación para ver cómo se ve hasta ahora. ¡Ya no hay más marcadores de posición! Estás comenzando bien.
Nota:
Si desea experimentar más, intente agregar un nuevo TextBlock a la plantilla de datos y use el truco x:Bind IntelliSense para buscar una propiedad que se va a mostrar.
Parte 2: Uso de la vinculación para conectar la interfaz de usuario de la galería a las imágenes
En esta sección, creará enlaces de una vez en la XAML de la página para conectar la vista de la galería a la colección de imágenes. Estos vínculos reemplazan el código procedimental existente en el código subyacente. También se crea un botón Eliminar para ver cómo cambia la vista de la galería al quitar imágenes de la colección. Al mismo tiempo, aprenderá a enlazar eventos a controladores de eventos para obtener más flexibilidad que los controladores de eventos tradicionales.
Todos los enlaces cubiertos hasta ahora están dentro de las plantillas de datos y hacen referencia a las propiedades de la clase indicadas por el valor de x:DataType. ¿Qué ocurre con el resto del XAML de la página?
x:Bind las expresiones fuera de las plantillas de datos siempre se vinculan a la propia página. Esto significa que puedes hacer referencia a todo lo que pongas en código subyacente o declares en XAML, incluidas las propiedades personalizadas y las propiedades de otros controles de interfaz de usuario de la página (siempre y cuando tengan un valor de x:Name).
En el ejemplo PhotoLab, se usa un enlace como este para conectar el control principal GridView directamente a la colección de imágenes, en lugar de hacerlo en código subyacente. Más adelante, verá otros ejemplos.
Enlace el control GridView principal a la colección Images
En MainPage.xaml.cs, busque el método
GetItemsAsyncy quite el código que estableceItemsSource.antes:
ImageGridView.ItemsSource = Images;después:
// Replaced with XAML binding: // ImageGridView.ItemsSource = Images;En MainPage.xaml, busque el
GridViewdenominadoImageGridViewy agregue un atributoItemsSource. Para el valor, use una expresiónx:Bindque hace referencia a la propiedadImagesimplementada en código subyacente.antes:
<GridView x:Name="ImageGridView"después:
<GridView x:Name="ImageGridView" ItemsSource="{x:Bind Images}"La propiedad
Imageses de tipoObservableCollection<ImageFileInfo>, por lo que los elementos individuales mostrados en elGridViewson de tipoImageFileInfo. Este tipo coincide con elx:DataTypevalor descrito en la parte 1.
Todos los enlaces que vio anteriormente son enlaces de solo lectura únicos, que es el comportamiento predeterminado de las expresiones sin formato x:Bind . Los datos solo se cargan en la inicialización, lo que hace que los enlaces de alto rendimiento sean perfectos para admitir varias vistas complejas de grandes conjuntos de datos.
Incluso el enlace de ItemsSource que acaba de agregar es un enlace de solo lectura a un valor de propiedad sin cambiar, pero aquí hay una distinción importante. El valor sin cambiar de la propiedad Images es una única instancia específica de una colección, inicializada una vez como se muestra aquí.
private ObservableCollection<ImageFileInfo> Images { get; }
= new ObservableCollection<ImageFileInfo>();
El valor de la propiedad Images nunca cambia, pero dado que la propiedad es de tipo ObservableCollection<T>, el contenido de la colección puede cambiar, y el enlace detecta automáticamente los cambios y actualiza la UI.
Para probar este comportamiento, agregue temporalmente un botón que elimine la imagen seleccionada actualmente. Este botón no está en la versión final porque seleccionar una imagen le lleva a una página de detalles. Sin embargo, el comportamiento de ObservableCollection<T> sigue siendo importante en el ejemplo final de PhotoLab porque el XAML se inicializa en el constructor de página a través de la llamada al método InitializeComponent, pero la colección Images se rellena más adelante en el método GetItemsAsync.
Agregar un botón eliminar
En MainPage.xaml, busque el
CommandBardenominado MainCommandBar y agregue un botón nuevo antes del botón de zoom. (Los controles de zoom aún no funcionan. Los enlazará en la siguiente parte del tutorial).<AppBarButton Icon="Delete" Label="Delete selected image" Click="{x:Bind DeleteSelectedImage}" />Si ya estás familiarizado con XAML, este valor de
Clickpodría parecer inusual. En versiones anteriores de XAML, tenías que establecerlo en un método con una firma específica del controlador de eventos, que normalmente incluía parámetros para el remitente del evento y un objeto de argumentos específicos del evento. Todavía puede usar esta técnica cuando necesite los argumentos de evento, pero conx:Bind, también puede conectarse a otros métodos. Por ejemplo, si no necesita los datos del evento, puede conectarse a métodos que no tengan parámetros, como hacemos aquí.En MainPage.xaml.cs, agregue el método
DeleteSelectedImage.private void DeleteSelectedImage() => Images.Remove(ImageGridView.SelectedItem as ImageFileInfo);Este método simplemente elimina la imagen seleccionada de la colección
Images.
Ahora ejecute la aplicación y use el botón para eliminar algunas imágenes. Como puede ver, la interfaz de usuario se actualiza automáticamente, gracias a la vinculación de datos y al tipo ObservableCollection<T>.
Nota:
Este código solo elimina la instancia de ImageFileInfo de la colección Images en la aplicación en ejecución. No elimina el archivo de imagen del equipo.
Parte 3: Configurar el control deslizante de zoom
En esta parte, crearás enlaces unidireccionales desde un control de la plantilla de datos hasta el control deslizante de zoom, que está fuera de la plantilla. También aprenderá que puede usar el enlace de datos con muchas propiedades de control, no solo las más obvias, como TextBlock.Text y Image.Source.
Vincula la plantilla de datos de imagen al control deslizante de zoom
Busque el
DataTemplatellamadoImageGridView_DefaultItemTemplatey reemplace los valores**Height**yWidthdel controlGriden la parte superior de la plantilla.antes de
<DataTemplate x:Key="ImageGridView_DefaultItemTemplate" x:DataType="local:ImageFileInfo"> <Grid Height="200" Width="200" Margin="{StaticResource LargeItemMargin}">después de
<DataTemplate x:Key="ImageGridView_DefaultItemTemplate" x:DataType="local:ImageFileInfo"> <Grid Height="{Binding Value, ElementName=ZoomSlider}" Width="{Binding Value, ElementName=ZoomSlider}" Margin="{StaticResource LargeItemMargin}">
¿Ha observado que se trata de expresiones Binding y no x:Bind expresiones? Esta es la forma antigua de realizar enlaces de datos y es principalmente obsoleta.
x:Bind hace casi todo lo que Binding hace, etc. Sin embargo, cuando se usa x:Bind en una plantilla de datos, se enlaza al tipo declarado en el valor de x:DataType. ¿Cómo enlazas algo de la plantilla a algo en la página XAML o en código subyacente? Debe usar una antigua expresión de estilo Binding.
Las expresiones de Binding no reconocen el valor de x:DataType, pero estas expresiones de Binding tienen valores de ElementName que funcionan de manera casi igual. Estos indican al motor de enlace que el valor de enlace es un enlace a la propiedad Value del elemento especificado en la página (es decir, el elemento con ese valor x:Name). Si quieres enlazar a una propiedad en código subyacente, tendría un aspecto similar al {Binding MyCodeBehindProperty, ElementName=page} en el que page hace referencia al valor de x:Name establecido en el elemento Page en XAML.
Nota:
De forma predeterminada, las expresiones de Binding son unamanera, lo que significa que actualizarán automáticamente la interfaz de usuario cuando cambie el valor de la propiedad enlazada.
En cambio, el valor predeterminado de x:Bind es unahora, lo que significa que se omiten los cambios realizados en la propiedad enlazada. Este es el valor predeterminado porque es la opción de alto rendimiento y la mayoría de los enlaces son datos estáticos y de solo lectura.
La lección aquí es que si usa x:Bind con propiedades que pueden cambiar sus valores, asegúrese de agregar Mode=OneWay o Mode=TwoWay. Verá ejemplos de esto en la sección siguiente.
Ejecute la aplicación y use el control deslizante para cambiar las dimensiones de la plantilla de imagen. Como puede ver, el efecto es bastante eficaz sin necesidad de mucho código.
Nota:
Para un desafío, intente enlazar otras propiedades de la interfaz de usuario a la propiedad Value del control deslizante de zoom, o a otros controles deslizantes que agregue después. Por ejemplo, podrías vincular la propiedad FontSize del TitleTextBlock a un nuevo control deslizante con un valor predeterminado de 24. Asegúrese de establecer valores mínimos y máximos razonables.
Parte 4: Mejora de la experiencia de zoom
En esta parte, agregarás una propiedad ItemSize personalizada al código detrás y crearás enlaces unidireccionales desde la plantilla de imagen hacia la nueva propiedad. El valor ItemSize se actualizará mediante el control deslizante de zoom y otros factores, como el conmutador Ajustar a la pantalla y el tamaño de la ventana, para ofrecer una experiencia más refinada.
A diferencia de las propiedades de control integradas, las propiedades personalizadas no actualizan automáticamente la interfaz de usuario, incluso con enlaces unidireccionales y bidireccionales. Funcionan bien con un solotiempo enlaces, pero si quiere que los cambios de propiedad se muestren realmente en la interfaz de usuario, debe realizar algún trabajo.
Cree la propiedad ItemSize para que actualice la interfaz de usuario.
En MainPage.xaml.cs, cambie la firma de la clase
MainPagepara que implemente la interfazINotifyPropertyChanged.antes:
public sealed partial class MainPage : Pagedespués:
public sealed partial class MainPage : Page, INotifyPropertyChangedEsto informa al sistema de enlace de que
MainPagetiene un eventoPropertyChanged(agregado a continuación) al que los enlaces pueden escuchar para actualizar la interfaz de usuario.Agregue un evento
PropertyChangeda la claseMainPage.public event PropertyChangedEventHandler PropertyChanged;Este evento proporciona la implementación completa requerida por la interfaz
INotifyPropertyChanged. Sin embargo, para que tenga cualquier efecto, debe generar explícitamente el evento en las propiedades personalizadas.Agregue una propiedad
ItemSizey genere el eventoPropertyChangeden su establecedor.public double ItemSize { get => _itemSize; set { if (_itemSize != value) { _itemSize = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ItemSize))); } } } private double _itemSize;La propiedad
ItemSizeexpone el valor de un campo_itemSizeprivado. El uso de un campo de respaldo como este permite a la propiedad comprobar si un nuevo valor es el mismo que el valor anterior antes de que genere un evento dePropertyChangedpotencialmente innecesario.El propio evento lo genera el método
Invoke. El signo de interrogación comprueba si el eventoPropertyChangedes null; es decir, si se ha agregado algún controlador de eventos todavía. Cada enlace unidireccional o bidireccional agrega un controlador de eventos en segundo plano, pero si nadie está escuchando, no ocurrirá más aquí. Sin embargo, siPropertyChangedno es null, se llama aInvokecon una referencia al origen del evento (la propia página, representada por la palabra clavethis) y un objeto event-args que indica el nombre de la propiedad. Con esta información, cualquier enlace unidireccional o bidireccional a la propiedadItemSizeserá informado de los cambios, para que pueda actualizar la interfaz de usuario vinculada.En MainPage.xaml, busque el
DataTemplatedenominadoImageGridView_DefaultItemTemplatey reemplace los valores deHeightyWidthdel controlGriden la parte superior de la plantilla. (Si ha realizado el enlace de control a control en la parte anterior de este tutorial, los únicos cambios son reemplazarValueporItemSizeyZoomSliderporpage. Asegúrese de hacerlo tanto paraHeightcomo paraWidth).)antes de
<DataTemplate x:Key="ImageGridView_DefaultItemTemplate" x:DataType="local:ImageFileInfo"> <Grid Height="{Binding Value, ElementName=ZoomSlider}" Width="{Binding Value, ElementName=ZoomSlider}" Margin="{StaticResource LargeItemMargin}">después de
<DataTemplate x:Key="ImageGridView_DefaultItemTemplate" x:DataType="local:ImageFileInfo"> <Grid Height="{Binding ItemSize, ElementName=page}" Width="{Binding ItemSize, ElementName=page}" Margin="{StaticResource LargeItemMargin}">
Ahora que la interfaz de usuario puede responder a ItemSize cambios, debe realizar algunos cambios. Como se mencionó anteriormente, el valor de ItemSize se calcula a partir del estado actual de varios controles de interfaz de usuario, pero el cálculo debe realizarse siempre que esos controles cambien de estado. Para ello, usará la vinculación de eventos para que determinados cambios en la interfaz de usuario llamen a un método auxiliar que actualice ItemSize.
Actualizar el valor de la propiedad ItemSize
Agregue el método
DetermineItemSizea MainPage.xaml.cs.private void DetermineItemSize() { if (FitScreenToggle != null && FitScreenToggle.IsOn == true && ImageGridView != null && ZoomSlider != null) { // The 'margins' value represents the total of the margins around the // image in the grid item. 8 from the ItemTemplate root grid + 8 from // the ItemContainerStyle * (Right + Left). If those values change, // this value needs to be updated to match. int margins = (int)this.Resources["LargeItemMarginValue"] * 4; double gridWidth = ImageGridView.ActualWidth - (int)this.Resources["DefaultWindowSidePaddingValue"]; double ItemWidth = ZoomSlider.Value + margins; // We need at least 1 column. int columns = (int)Math.Max(gridWidth / ItemWidth, 1); // Adjust the available grid width to account for margins around each item. double adjustedGridWidth = gridWidth - (columns * margins); ItemSize = (adjustedGridWidth / columns); } else { ItemSize = ZoomSlider.Value; } }En MainPage.xaml, vaya a la parte superior del archivo y agregue un enlace de eventos
SizeChangedal elementoPage.antes:
<Page x:Name="page"después:
<Page x:Name="page" SizeChanged="{x:Bind DetermineItemSize}"Busque el
SliderdenominadoZoomSlider(en la secciónPage.Resources) y añada una vinculación de eventoValueChanged.antes:
<Slider x:Name="ZoomSlider"después:
<Slider x:Name="ZoomSlider" ValueChanged="{x:Bind DetermineItemSize}"Busque el
ToggleSwitchdenominadoFitScreenToggley agregue una vinculación de eventoToggled.antes:
<ToggleSwitch x:Name="FitScreenToggle"después:
<ToggleSwitch x:Name="FitScreenToggle" Toggled="{x:Bind DetermineItemSize}"
Ejecute la aplicación y use el control deslizante de zoom y Ajustar a la pantalla alternar para cambiar las dimensiones de la plantilla de imagen. Como puede ver, los cambios más recientes permiten una experiencia de zoom y cambio de tamaño más refinada mientras mantiene bien organizado el código.
Nota:
Si buscas un reto, intenta añadir un TextBlock después del ZoomSlider y vincular la propiedad Text a la propiedad ItemSize. Dado que no está en una plantilla de datos, puede usar x:Bind en lugar de Binding como en los enlaces de ItemSize anteriores.
Parte 5: Habilitar ediciones de usuario
Aquí, creará enlaces bidireccionales para permitir que los usuarios actualicen los valores, incluido el título de la imagen, la clasificación y varios efectos visuales.
Para lograrlo, actualizará el DetailPageexistente, que proporciona un visor para imágenes individuales, un control de zoom y una interfaz de usuario de edición.
En primer lugar, debe adjuntar el DetailPage para que la aplicación navegue a ella cuando el usuario haga clic en una imagen en la vista de la galería.
Adjuntar la página detallada
En MainPage.xaml, busque el
GridViewdenominadoImageGridView. Para que los elementos sean clicables, establezcaIsItemClickEnabledenTruey agregue un controlador de eventosItemClick.Sugerencia
Si escribe el cambio siguiente en lugar de copiar o pegar, aparecerá un mensaje emergente de IntelliSense con el texto "<Nuevo controlador de eventos>". Si presiona la tecla Tab, rellenará el valor con un nombre de controlador de método predeterminado y eliminará automáticamente el código auxiliar del método que se muestra en el paso siguiente. A continuación, puede presionar F12 para ir al método en el código subyacente.
antes:
<GridView x:Name="ImageGridView">después:
<GridView x:Name="ImageGridView" IsItemClickEnabled="True" ItemClick="ImageGridView_ItemClick">Nota:
Aquí se usa un controlador de eventos convencional en lugar de una expresión x:Bind. Esto se debe a que necesitamos ver los datos del evento, como se muestra a continuación.
En MainPage.xaml.cs, agregue el controlador de eventos (o llenelo, si usó la sugerencia en el último paso).
private void ImageGridView_ItemClick(object sender, ItemClickEventArgs e) { this.Frame.Navigate(typeof(DetailPage), e.ClickedItem); }Este método, que simplemente navega a la página de detalles, pasando el elemento en el que se hizo clic, es un objeto
ImageFileInfoutilizado por DetailPage.OnNavigatedTo para inicializar la página. No tendrá que implementar ese método en este tutorial, pero puede echar un vistazo a lo que hace.(Opcional) Elimine o convierta en comentario los controles que haya agregado en los puntos de reproducción anteriores que funcionan con la imagen seleccionada actualmente. Tenerlos a mano no dañará nada, pero ahora es mucho más difícil seleccionar una imagen sin navegar a la página de detalles.
Ahora que ha conectado las dos páginas, ejecute la aplicación y eche un vistazo. Todo funciona excepto los controles del panel de edición, que no responden al intentar cambiar los valores.
Como puede ver, el cuadro de texto título muestra el título y le permite escribir los cambios. Tiene que cambiar el foco a otro control para confirmar los cambios, pero el título de la esquina superior izquierda de la pantalla aún no se actualiza.
Todos los controles ya están enlazados mediante las expresiones x:Bind que se trataron en la Parte 1. Recuerde que esto significa que son vinculaciones únicas, lo que explica por qué los cambios en los valores no se registran. Para corregir esto, todo lo que tenemos que hacer es convertirlos en enlaces bidireccionales.
Hacer que los controles de edición sean interactivos
En DetailPage.xaml, busque el
TextBlockdenominado TitleTextBlock y el RatingControl control después de él, y actualice sus expresiones dex:Bindpara incluir Mode=TwoWay.antes:
<TextBlock x:Name="TitleTextBlock" Text="{x:Bind item.ImageTitle}" ... > <muxc:RatingControl Value="{x:Bind item.ImageRating}" ... >después:
<TextBlock x:Name="TitleTextBlock" Text="{x:Bind item.ImageTitle, Mode=TwoWay}" ... > <muxc:RatingControl Value="{x:Bind item.ImageRating, Mode=TwoWay}" ... >Haga lo mismo para todos los controles deslizantes de efecto que se encuentran después del control de valoración.
<Slider Header="Exposure" ... Value="{x:Bind item.Exposure, Mode=TwoWay}" ... <Slider Header="Temperature" ... Value="{x:Bind item.Temperature, Mode=TwoWay}" ... <Slider Header="Tint" ... Value="{x:Bind item.Tint, Mode=TwoWay}" ... <Slider Header="Contrast" ... Value="{x:Bind item.Contrast, Mode=TwoWay}" ... <Slider Header="Saturation" ... Value="{x:Bind item.Saturation, Mode=TwoWay}" ... <Slider Header="Blur" ... Value="{x:Bind item.Blur, Mode=TwoWay}" ...
El modo bidireccional, como podría esperar, significa que los datos se mueven en ambas direcciones siempre que haya cambios en cualquiera de los lados.
Al igual que los enlaces unidireccionales descritos anteriormente, estos enlaces bidireccionales ahora actualizarán la interfaz de usuario cada vez que cambien las propiedades enlazadas, gracias a la implementación de INotifyPropertyChanged en la clase ImageFileInfo. Sin embargo, con el enlace bidireccional, los valores también se moverán de la interfaz de usuario a las propiedades enlazadas siempre que el usuario interactúe con el control. No se necesita nada más en el lado XAML.
Ejecute la aplicación y pruebe los controles de edición. Como puede ver, cuando se realiza un cambio, ahora afecta a los valores de imagen y esos cambios se conservan al volver a la página principal.
Parte 6: Dar formato a los valores a través del enlace de funciones
Queda un último problema. Al mover los controles deslizantes de efecto, las etiquetas situadas junto a ellas aún no cambian.
La parte final de este tutorial es agregar vinculaciones que formateen los valores del control deslizante para su visualización.
Vincula las etiquetas del deslizador de efecto y formatea los valores para mostrarlos
Busque el
TextBlockdespués del control deslizanteExposurey reemplace el valor deTextpor la expresión de enlace que se muestra aquí.antes:
<Slider Header="Exposure" ... /> <TextBlock ... Text="0.00" />después:
<Slider Header="Exposure" ... /> <TextBlock ... Text="{x:Bind item.Exposure.ToString('N', culture), Mode=OneWay}" />Esto se denomina enlace de función porque se enlaza al valor devuelto de un método. El método debe ser accesible a través del código subyacente de la página o el tipo
x:DataTypecuando se encuentre en una plantilla de datos. En este caso, el método es el conocido métodoToString.NET, al que se accede a través de la propiedad item de la página y, a continuación, a través de la propiedadExposuredel elemento. (Esto muestra cómo se puede enlazar a métodos y propiedades que están profundamente anidados en una cadena de conexiones).El enlace de funciones es una manera ideal de formatear los valores para su visualización, ya que puede enviar otros orígenes de enlace como argumentos de método y la expresión de enlace monitorizará los cambios en esos valores como se espera con el modo unidireccional. En este ejemplo, el argumento de la cultura es una referencia a un campo inmutable implementado en el código detrás, pero podría ser fácilmente una propiedad que genera eventos
PropertyChanged. En ese caso, cualquier cambio en el valor de la propiedad haría que la expresiónx:Bindllamara aToStringcon el nuevo valor y, a continuación, actualizaría la interfaz de usuario con el resultado.Haga lo mismo para las etiquetas
TextBlockque etiquetan los demás controles deslizantes de efecto.<Slider Header="Temperature" ... /> <TextBlock ... Text="{x:Bind item.Temperature.ToString('N', culture), Mode=OneWay}" /> <Slider Header="Tint" ... /> <TextBlock ... Text="{x:Bind item.Tint.ToString('N', culture), Mode=OneWay}" /> <Slider Header="Contrast" ... /> <TextBlock ... Text="{x:Bind item.Contrast.ToString('N', culture), Mode=OneWay}" /> <Slider Header="Saturation" ... /> <TextBlock ... Text="{x:Bind item.Saturation.ToString('N', culture), Mode=OneWay}" /> <Slider Header="Blur" ... /> <TextBlock ... Text="{x:Bind item.Blur.ToString('N', culture), Mode=OneWay}" />
Cuando ejecutas la aplicación, todo funciona, incluidas las etiquetas del control deslizante.
Diferencias entre Binding y x:Bind
Al crear enlaces de datos en XAML en las aplicaciones para UWP, puedes elegir entre Binding y x:Bind. Estas son las principales diferencias:
-
x:Bind: proporciona validación en tiempo de compilación, un mejor rendimiento y tiene una tipificación fuerte. Es más adecuado para escenarios en los que se conoce la estructura de datos en tiempo de compilación. -
Binding: ofrece una evaluación en tiempo de ejecución y una mayor flexibilidad para escenarios dinámicos, como cuando la estructura de datos se determina en tiempo de ejecución.
Escenarios no admitidos por x:Bind
Aunque x:Bind es muy eficaz, tiene limitaciones en determinados escenarios:
-
Estructuras de datos dinámicas:
x:Bindno se puede usar cuando la estructura de datos se determina en tiempo de ejecución. -
Enlace de elemento a elemento: el enlace directo entre dos elementos de la interfaz de usuario no es compatible con
x:Bind. -
Herencia de DataContext: a diferencia de
Binding,x:Bindno hereda automáticamente elDataContextde un elemento primario. -
Enlaces bidireccionales:
x:Bindadmite enlaces bidireccionales, lo que permite que los cambios fluyan de la interfaz de usuario de vuelta a la propiedad de origen. Para que la interfaz de usuario se actualice cuando cambie la propiedad de origen (en enlaces unidireccionales o bidireccionales), debe implementarINotifyPropertyChangeden los objetos de datos.
Para obtener más detalles y ejemplos, consulte los siguientes recursos:
Conclusión
Este tutorial le ha dado una idea del enlace de datos y le ha mostrado algunas de las funcionalidades disponibles. Una palabra de precaución antes de encapsular: no todo es enlazable y, a veces, los valores a los que intenta conectarse son incompatibles con las propiedades que está intentando enlazar. Hay mucha flexibilidad en la vinculación, pero no funcionará en todas las situaciones.
Un ejemplo de un problema no solucionado por la vinculación es cuando un control no tiene propiedades adecuadas para enlazar, como con la característica de zoom de la página de detalles. Este control deslizante de ampliación debe interactuar con el ScrollViewer que muestra la imagen, pero ScrollViewer solo se puede actualizar a través de su método ChangeView. En este caso, usamos controladores de eventos convencionales para mantener la ScrollViewer y el control deslizante de zoom sincronizados; Consulte los métodos ZoomSlider_ValueChanged y MainImageScroll_ViewChanged en DetailPage para obtener más información.
Sin embargo, el enlace es una manera eficaz y flexible de simplificar el código y mantener la lógica de la interfaz de usuario separada de la lógica de datos. Esto le hará mucho más fácil ajustar cualquiera de los lados de esta división, a la vez que reduce el riesgo de introducir errores en el otro lado.
Un ejemplo de separación de datos y interfaz de usuario es con la propiedad ImageFileInfo.ImageTitle. Esta propiedad (y la propiedad ImageRating) es ligeramente diferente de la propiedad ItemSize que creó en la parte 4 porque el valor se almacena en los metadatos del archivo (expuestos a través del tipo ImageProperties) en lugar de en un campo. Además, ImageTitle devuelve el valor ImageName (establecido en el nombre de archivo) si no hay ningún título en los metadatos del archivo.
public string ImageTitle
{
get => String.IsNullOrEmpty(ImageProperties.Title) ? ImageName : ImageProperties.Title;
set
{
if (ImageProperties.Title != value)
{
ImageProperties.Title = value;
var ignoreResult = ImageProperties.SavePropertiesAsync();
OnPropertyChanged();
}
}
}
Como puede ver, el establecedor actualiza la propiedad ImageProperties.Title y, a continuación, llama a SavePropertiesAsync para escribir el nuevo valor en el archivo. (Este es un método asincrónico, pero no podemos usar la palabra clave await en una propiedad, y además no querrías hacerlo porque los getters y setters de propiedades deben completarse de inmediato. Así que, en su lugar, llame al método e ignore el objeto Task que devuelve).
Ir más lejos
Ahora que ha completado este laboratorio, tiene suficientes conocimientos sólidos para abordar un problema por su cuenta.
Como es posible que haya observado, si cambia el nivel de zoom en la página de detalles, se restablece automáticamente al navegar hacia atrás y, a continuación, vuelve a seleccionar la misma imagen. ¿Puede averiguar cómo conservar y restaurar el nivel de zoom de cada imagen individualmente? ¡Buena suerte!
Deberías tener toda la información que necesitas en este tutorial, pero si necesitas más orientación, la documentación de vinculación de datos está solo a un clic. Comience aquí: