2010-09-04 10 views
11

O ", ¿cómo hacer que todas sus fijaciones permanecen correcta?"
(esto es un poco largo, pero tengan paciencia conmigo, he intentado que sea lo más corto que pude)verificación estática de las consolidaciones

Consideremos el siguiente ejemplo:

<TextBox Name="tb" /> 
    <TextBlock Text="{Binding Text.TheProp, ElementName=tb}" /> 

está perfectamente conocido en tiempo de compilación que la unión es incorrecta (es decir, el analizador sabe el tipo de elemento tb, y por lo tanto, se conoce el tipo de es 0,propiedad, y por lo tanto, sabe que TheProp no existe).
Sin embargo, este código se compilará y ejecutará (aunque con un mensaje de error vinculante en la salida de depuración).

Este comportamiento puede ser muy útil en algunas situaciones: no importa de qué tipo exacto sean mis datos, siempre y cuando tenga las propiedades apropiadamente nombradas, estoy bien. Por lo tanto, obtenemos un tipo de "tipa declarativa de pato".

Sin embargo,, tipar pato no siempre es algo bueno.
Específicamente, al usar el patrón MVVM, sé ​​(la mayoría de las veces) los tipos exactos de todos mis objetos de ViewModel. Por otro lado, los modelos se vuelven cada vez más complejos con el tiempo, lo que me preocupa por la futura refactorización: ¿qué ocurre si decido cambiar el nombre de algunas propiedades o, Dios no lo permita, ponerlas en un objeto agregado separado? ¿Qué va a pasar con todas mis ataduras entonces? ¿Tendré que rastrillar todos los archivos XAML a mano? E incluso sin refactorizar, ¿qué pasa si simplemente hago un error tipográfico?

Un problema similar ya está resuelto en otros lugares de XAML. Si, por ejemplo, pone un nombre de propiedad incorrecto en Style/Setter/@Property, obtendrá un error de tiempo de compilación.
TemplateBinding también proporciona dicha verificación. Lo cual es muy útil.

Así, idealmente, me gustaría ver algo como esto:

ProductViewModel.cs:

public class ProductViewModel 
    { 
     public Name { get; set; } 
     public Price { get; set; } 
    } 

ProductView.XAML:

<UserControl x:Class="Shopping.View.ProductView" 
       x:DataContextType="vm:ProductViewModel" 
       xmlns:vm="clr-namespace:Shopping.ViewModel" 
       ... > 
     <TextBox Text="{Binding Name}" /> <!-- OK --> 
     <TextBox Text="{Binding Price}" /> <!-- OK --> 
     <TextBox Text="{Binding ABC}" /> <!-- Compile time error: there is no property ABC in ProductViewModel --> 
    </UserControl> 

ShoppingCart. XAML:

<UserControl x:Class="Shopping.View.ShoppingCartView" 
       x:DataContextType="vm:ShoppingCartViewModel" 
       xmlns:vm="clr-namespace:Shopping.ViewModel" 
       ... > 
     <ItemsControl ItemsSource="{Binding Products}" 
         ItemType="vm:ProductViewModel" > <!-- Static check happens here 
                  ShoppingCartViewModel.Products must 
                  implement IEnumerable<ProductViewModel> --> 
      <ItemsControl.ItemTemplate> 
       <DataTemplate DataType="vm:ProductViewModel"> 
        <view:ProductView /> <!-- DataContext is known to be of correct type 
               because of DataTemplate.DataType property --> 
       </DataTemplate> 
      </ItemsControl.ItemTemplate> 
     </ItemsControl> 
    </UserControl> 

Pero volvamos a la realidad. En realidad, todo ese sueño no va a suceder en el futuro cercano.

Sin embargo, estoy seguro de que no soy la primera persona en tener este problema.
Así que, finalmente, la pregunta es: ¿Cómo se asegura de que sus enlaces sean correctos? ¿Y que permanezcan así?

+0

UWP ahora proporciona enlace estático a través de la extensión de marcado ['{x: Bind}'] (https://docs.microsoft.com/en-us/windows/uwp/xaml-platform/x-bind-markup- extensión). Maneras misteriosas :) – Funk

Respuesta

8

¿Qué tal el análisis estático de su Xaml realizado como un paso posterior a la construcción?

Como parte de .Net 4, Microsoft lanzó una nueva biblioteca System.Xaml para proporcionar un robusto soporte de serialización y análisis Xaml independiente de WPF. Ahora están comenzando a construir todo tipo de cosas interesantes, algunas de las cuales pueden ayudarte.

En el XamlToolkit, por ejemplo, encontrará el XamlDOM que le permite realizar análisis estáticos sencillos de los archivos Xaml. Y llevando eso un poco más allá, está FxCop rules for XAML.

De mayor interés es BindingFinder de Rob Relyea que tiene el objetivo explícito de comprobar el tipo de Vinculaciones en Xaml. Esto requiere que tenga sugerencias de tipo en su Xaml, como el atributo DataType en un DataTemplate, o el nuevo d:DataContext attribute en sus Vistas (que Blend utiliza para proporcionar datos en tiempo de diseño). Luego usa el XamlDOM para verificar que todo coincida.

Actualización:Resharper 6 ahora proporciona intellisense for data bindings, y las advertencias si obtiene sus caminos de propiedad mal.

+0

... ¡Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa! pero tener un lugar para comenzar siempre es mejor.:-) –

+0

@Fyodor - ¡me alegro de haber podido servir! –

+0

¡Visual Studio 2010 y XAML necesitan la funcionalidad "BindingFinder" lista para usar! – thenonhacker

2

Como una cuestión práctica, nunca he encontrado que esto sea un problema, al menos cuando se usa el patrón MVVM. El modelo de vista solo existe en apoyo de la vista. No voy a cambiar uno sin cambiar el otro. Refactorizar el modelo de vista no va a romper los enlaces en la vista porque no tiene sentido refactorizar el modelo de vista por sí mismo.Solo refactorizará el modelo de vista cuando (y debido a) cambie el diseño de la vista.

La otra razón por la que no tengo este problema es porque no estoy desarrollando el modelo de vista independientemente de Expression Blend. Para todas las interfaces de usuario menos triviales, construyo mis modelos de vista utilizando algún tipo de inyección de dependencia para poder crear una fuente de datos de prueba que se pueda usar en Expression Blend. Cuando creo enlaces en Blend, sé de inmediato si lo he hecho bien o no.

Al igual que con MVVM en general, hacer esto es un dolor increíble en el culo hasta que comprenda lo que está haciendo y por qué. (This long blog post por Jonas Follesø ofrece una visión bastante buena de cómo usar Ninject para este propósito, aunque no hay ningún final de otros marcos que pueda usar.) Estoy seguro de que hay problemas que aún no he descubierto con esta metodología - Más allá del problema que he agregado marcos DI y Expression Blend en el montón de cosas que necesito entender para desarrollar aplicaciones WPF.

Pablo Casals dijo que la constante experimentación mantiene al artista joven. Yo no siento joven.

+2

Bueno, parece que entendemos MVVM de manera diferente. Cuando llegué a entenderlo, uno debería pensar en ViewModel a partir de la interfaz de usuario real de la aplicación, mientras que View es una especie de "máscara" para esa interfaz de usuario. Puedo citar, por ejemplo, este artículo: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx Este enfoque permitió algunas cosas buenas. Por ejemplo: uno puede tener más de un "aspecto" para la misma interfaz de usuario. Otro ejemplo: "piel" se puede diseñar [relativamente] independientemente de la interfaz de usuario en sí, y por una persona diferente, también (generalmente conocido como un "diseñador" :-). [continúa en el siguiente comentario] –

+1

Otro ejemplo más: en el caso de varias "máscaras", algunas de ellas pueden diseñarse de forma independiente, por una persona diferente, por una empresa diferente o incluso por el cliente. Y, por supuesto, ¿qué hay de las pruebas unitarias? Si ve ViewModel como "soporte" para View, siempre debe tener en cuenta View al diseñar pruebas de unidades. E incluso desde su punto de vista, todavía no funciona: si la Vista está siendo diseñada por una persona diferente ("diseñador"), ¿cómo va a cambiarla junto con ViewModel? –

+1

Y, por último, con respecto a la necesidad de refactorización. También me gustaría diferir en esta parte.La refactoración se utiliza regularmente cuando el sistema se vuelve demasiado complejo, por lo que necesita descomponerse en sistemas más simples o reorganizar sus componentes de una manera diferente. Un ejemplo simple: supongamos que una pantalla debe mostrar cierta información sobre algún producto. Diga, nombre y precio. Entonces mi ViewModel tiene esas propiedades y la vista se une a ellas. Entonces viene un requisito: agregue un campo "fabricante". Solo una cadena simple. OK hecho. Ahora mi ViewModel tiene otra propiedad llamada "Manufacturer". [Vea el siguiente comnt] –

Cuestiones relacionadas