2010-08-28 21 views
27

Estoy tratando de aprender WPF, pero me resulta muy difícil entender las vinculaciones, lo de "recursos" y la creación de objetos. Mi fondo está en C++/MFC y C# -Winforms.Principiante: confundido sobre el enlace y los recursos en WPF

Mis preguntas:

  1. mayoría de los ejemplos que veo en XAML (en MSDN y en otros dos libros que he leído WPF) utilizan StaticResource en la expresión de enlace. ¿Están relacionados de alguna manera con los miembros estáticos? ¿O es solo un nombre engañoso? Cuando se hace referencia a cualquier objeto como StaticResource, ¿cuándo se instancia?

  2. Por lo que yo puedo ver StaticResources se utilizan con "cosas" definidos en la sección "Recursos" de la aplicación/ventana/control, etc.
    Ahora, estas secciones de recursos son muy confuso para mí. ¿Qué son exactamente? Desde mi experiencia en MFC estos fueron iconos, cadenas, etc. Sin embargo, a juzgar por todos los ejemplos que he visto, en WPF estos parecen ser esencialmente un "vertedero" para (a) todo tipo de definiciones de objetos globales en marcado (estilos, plantillas de datos, etc.) (b) todo tipo de instanciaciones de objetos globales en el marcado ¿Estoy en lo correcto? Esto me parece muy complicado.
    Básicamente, se trata de aprender todo tipo de semi-DSL en XAML (para definir estilos, definir plantillas de datos, crear objetos, etc.) y pegarlas en el mismo lugar. Sigo pensando en algo como editar manualmente el archivo de recursos (.rc) en MFC. Al menos allí las secciones estaban bien separadas y la sintaxis de cada recurso era relativamente simple.

  3. Para atar las dos preguntas anteriores: Cuando defino una instancia de objeto en la sección Recursos, y luego la hago referencia desde un enlace StaticResource, ¿cuándo exactamente se instancia? MSDN dice (en "Cómo: Hacer disponible de datos para Encuadernación en XAML"):

una forma que puede hacer que el objeto disponible para la unión es definirla como un recurso

Sin embargo, esto no es muy claro. ¿Qué significan disponibles? ¿Significan creado? ¿Significan que están conectados al subsistema de enlace? Y cuando exactamente es ese objeto creado? Al jugar con un ejemplo simple, vi que WPF parece crear este objeto para mí cuando intenta adjuntar el enlace. Y esto es aún más confuso.

EDIT: Después de la aclaración por karmicpuppet a continuación, todavía estoy confundido en cuanto a cómo está conectado a la vinculación. Supongamos que tengo en mis recursos:

<local:Person x:Key="MyPerson" Name="Title"/> 

(donde la persona es una clase con una propiedad llamada Nombre) y luego en la ventana que tengo:

<TextBlock Text="{Binding Source={StaticResource MyPerson}, Path=Name}"/> 

1) ¿Qué hace esto? ¿Sigue los mismos pasos, buscando el recurso y luego aplicándolo a la propiedad Text? ¿El objeto MyPerson se crea en el momento de la creación de la ventana, o más tarde? 2) ¿Tengo que usar el mecanismo de enlace para enlazar a la propiedad Nombre? ¿No puedo enlazarlo directamente como lo hizo anteriormente con myBrush? ¿Por qué no puedo hacer algo como esto?

<TextBlock Text="{StaticResource MyPerson, Path=Name}"/> 

¿Es solo una miopía por parte del marco? Creo que me estoy perdiendo mucho de aquí, pero parece que no entiendo qué ...

3) Intenté usar DynamicResource, pero estoy muy confundido sobre cada paso que tomé. a) Se ha añadido una DependencyObject con un DependencyProperty por encima de mi clase de ventana única en el código (es necesario DependencyObject?)

public class SomeText : DependencyObject 
{ 
    public string Header 
    { 
     get { return (string)GetValue(HeaderProperty); } 
     set { SetValue(HeaderProperty, value); } 
    } 
    public static readonly DependencyProperty HeaderProperty = 
     DependencyProperty.Register("Header", typeof(string), typeof(SomeText), new UIPropertyMetadata(0)); 
} 

b) que se añade una instancia del mismo a los Windows.Resources (es esto necesario con DynamicResource? MSDN parece decir que no, pero si lo que no puedo encontrar la manera de hacer el siguiente paso en XAML)

c) he intentado tanto:

Text="{Binding Source={DynamicResource HeaderText}, Path=Header}" 

Lo que me dio una excepción, y

Text="{DynamicResource HeaderText}" 

Pero yo no podía entender dónde poner la ruta de la propiedad de la cabecera.

Este es mi 5 o más intento de juguetear con WPF últimamente, y cada vez me deja perplejo por estas cosas aparentemente simples que no funcionan. He leído 2 libros y realmente trato de entender los artículos de MSDN, sin embargo, no son de ninguna ayuda en absoluto.

+1

Espere a que necesite una animación sobre la marcha. – Blindy

Respuesta

14

Piénselo de esta manera: todos los FrameworkElements (Windows, botones, otros controles, etc.), así como el objeto Application, contienen un Dictionary of Resources. Siempre que defina un recurso en XAML como se muestra aquí:

<Window> 
    <Window.Resources> 
    <SolidColorBrush x:Key="myBrush" Color="Red"/> 
    <DataTemplate x:Key"myTemplate"> 
     <!--Template definition here --> 
    </DataTemplate> 
    </Window.Resources> 
</Window> 

Es como hacer algo como esto en código:

class Window 
{ 
    void Window() 
    { 
    this.Resources.Add("myBrush", new SolidColorBrush(Brushes.Red)); 
    this.Resources.Add("myTemplate", new DataTemplate()); 
    } 
} 

Usted puede poner todo tipo de objetos como recursos. Cualquier cosa que desee volver a usar en su aplicación, puede definirla como un Recurso.

Ahora, cuando usted hace uso de un "{} StaticResource" de la siguiente manera:

<Button Background="{StaticResource myBrush}"/> 

Esto es como decir a WPF para buscar el recurso correspondiente "myBrush" y aplicarlo a la propiedad de fondo. Lo que sucederá es que WPF buscará primero el recurso en el diccionario de recursos del Botón, y si no lo encuentra buscará en su padre, luego en el padre de los padres, y así sucesivamente hasta los recursos de la aplicación.

Lo "estático" en "StaticResource" simplemente lo distingue del otro tipo de búsqueda de recursos llamado "DynamicResource". La diferencia entre los dos se responde en this link.

Cuando se aplica a Encuadernación, también funciona de la misma manera.Digamos, por ejemplo, tiene el siguiente recurso en su XAML:

<local:Person x:Key="MyPerson" Name="Title"/> 

y lo usamos como:

<TextBlock Text="{Binding Source={StaticResource MyPerson}, Path=Name}"/> 

En este caso, lo que va a pasar es algo como esto:

Binding b = new Binding(); 
b.Source = FindResource("MyPerson"); 
b.Path = "Name"; 
[TextBlock].SetBinding(TextBlock.TextProperty, b); 

Nuevamente, el marcado "{StaticResource}" en el XAML le dice a WPF que busque el recurso correspondiente y lo configure como el valor de la propiedad a. En este caso, la propiedad es la propiedad "Fuente" de Binding.

Eso es lo básico. Esperamos que encuentre útil esta información

+0

Está bien, gracias, pero todavía no tengo claro cómo se conecta todo al sistema de encuadernación. Supongamos que tengo en mis recursos: (donde Persona es una clase con una propiedad llamada Nombre) y luego en la ventana Tengo: 1) ¿Qué hace esto? ¿Sigue los mismos pasos, buscando el recurso y luego aplicándolo a la propiedad Text? 2) ¿Tengo que usar el mecanismo de enlace para enlazar a la propiedad Nombre? ¿No puedo enlazarlo directamente como lo hizo anteriormente con myBrush? – OrWhen

+0

Movido arriba del comentario a la pregunta real. Entonces * es * un vertedero para todo tipo de "cosas". Es solo un vertedero jerárquico. Estupendo. Lo que siento para mí es que estos "recursos" nunca fueron creados para ser editados por humanos o incluso legibles por humanos, sino para ser generados por herramientas. Encuentro que XAML es un sustituto muy pobre del código. ¿O es solo porque soy un principiante? – OrWhen

+1

He actualizado mi respuesta para incluir un poco sobre StaticResources and Binding. Esto responde su primera pregunta. En cuanto a su segunda pregunta, bueno, necesita la propiedad "Nombre" de un objeto "Persona", así que sí, tendrá que usar un Enlace para llegar a dicha propiedad. Básicamente, necesita dos cosas para establecer la propiedad Text del Bloque de texto: 1) el objeto Persona (que puede "buscarse" a través de "{StaticResource}"), y 2) especificar que desea la propiedad "Nombre" (que era establecido a través de "{Binding Path = Name}"). Espero que esto tenga sentido. – ASanch

38

primer lugar, un comentario general:

WPF es difícil de aprender. Es difícil de aprender porque hay varios conceptos diferentes y fundamentalmente nuevos con los que tienes que entender al mismo tiempo. La lucha que está teniendo en este momento es que usted está tratando de aprender por lo menos tres cosas a la vez:

  • Cómo la XamlReader (y extensiones particularmente marcado) deserializa XAML en objetos.
  • Cómo funcionan los diccionarios de recursos FrameworkElement.
  • Cómo funciona el enlace de datos.

Algo como esto:

<TextBox Text="{Binding Source={StaticResource MyPerson}, Path=Name}"/> 

se está activando (al menos) tres tecnologías muy diferentes al mismo tiempo. Esas tecnologías están diseñadas para ser lo más flexibles posible, lo que las hace más confusas para el principiante. La idea de que una fuente vinculante puede ser casi cualquier cosa: eso es difícil de entender. La idea de que una extensión de marcado es un tipo especial de formato de serialización que admite la recursión: lo suficientemente simple como para entenderla en principio, pero un poco desconcertante cuando comienzas a trabajar con ejemplos del mundo real. La idea de que un diccionario de recursos puede contener casi cualquier cosa, y que el algoritmo de búsqueda de recursos esencialmente hace que los recursos sean heredables: de nuevo, es bastante simple en concepto, pero es fácil perder el hilo cuando intentas descubrir el enlace de datos y XAML en al mismo tiempo.

Es frustrante, porque algo que es conceptualmente simple - "Quiero vincular este control a una propiedad de un objeto que he creado" - requiere que entienda muchas cosas antes de poder expresarlo en XAML.

La única solución es ser paciente y asegurarse de que entiende las cosas al nivel más bajo posible. Cuando vea esto:.

{StaticResource MyPerson} 

usted debe ser capaz de pensar, "Eso va a invocar el controlador de extensión StaticResource marcado, que recupera un objeto de un diccionario de recursos utilizando la tecla MyPerson cuando se deserializa el XAML

Al principio es extremadamente desafiante. He estado desarrollando software profesionalmente durante 35 años, y he descubierto que WPF es la plataforma tecnológica más desafiante que he aprendido por un margen considerable. Pero todo esto es difícil para aprender porque es increíblemente funcional y flexible. Y la recompensa de aprender es enorme.

para hacer frente a un par de cuestiones que karmicpuppet no:

Desde mi experiencia en MFC [recursos] eran iconos, cuerdas, etc.

que no ha cambiado. Aún puede crear archivos de recursos en WPF y cargarlos en objetos en tiempo de ejecución. Hay muchas maneras diferentes de hacerlo: puede crear recursos en el editor de recursos y cargarlos a través del objeto Properties.Resources, puede agregar archivos de imagen (por ejemplo) al proyecto, compilarlos como recursos y cargarlos usando su URI, y hay muchas otras formas que desconozco.

Los recursos disponibles para FrameworkElement s a través de sus diccionarios de recursos son algo diferente. Especie de. He aquí un ejemplo:

<Window.Resources> 
    <Image x:Key="MyImage" Source="images/myimage.png"/> 
</Window.Resources> 

Esto crea un objeto Image y lo agrega al diccionario de recursos del Window 's con una clave de MyImage Puede hacer referencia a ese objeto a través de la extensión StaticResource marcado en XAML, o el método FindResource en código.

se establece el atributo Source en el elemento Image en XAML también hace que el XamlReader utilice el ResourceManager para leer los datos de la imagen de recursos compilados del proyecto en tiempo de ejecución cuando se crea el objeto Image.

En la práctica, esto no es tan confuso como cuando usted está aprendiendo WPF por primera vez. Nunca recibo recursos que ResourceManager cargas y recursos almacenados en diccionarios de recursos mezclados.

¿Y cuándo exactamente es ese objeto creado?

Cualquier objeto definido por un elemento XAML se crea cuando el XamlReader lee el elemento. Así que esto:

<Window.Resources> 
    <local:Person x:Key="MyPerson"/> 
</Window.Resources> 

instancia un nuevo objeto Person y lo agrega al diccionario de recursos del Window 's con una clave de MyPerson. Es exactamente lo mismo que hacer esto en el código subyacente Window 's:

AddResource("MyPerson", new Person()); 

Entonces, ¿por qué no simplemente lo hacen en código subyacente? Dos razones:

Primero, es consistente. Si define todos sus recursos en XAML, solo necesita buscar en los archivos XAML para encontrar cuáles son sus recursos. Si los defines tanto en XAML como en código subyacente, debes buscar en dos lugares.

En segundo lugar, el IDE conoce los recursos que usted define en XAML. Si escribe

<TextBox Text="{Binding {StaticResource MyPerson}, Path=Name}"/> 

en su XAML, el IDE le permitirá saber si no se ha definido, en algún lugar en la jerarquía de los diccionarios de recursos, un recurso cuya clave es MyPerson.Pero no sabe acerca de los recursos que ha agregado en el código, por lo que, aunque el recurso puede encontrarse en tiempo de ejecución, el IDE lo informará como un problema.

+0

+1 Gran respuesta. – crypted

+0

Eso me alivia un poco, me alegro de que no soy el único que encuentra wpf difícil de entender, ¡pero finalmente increíble! – Mafii

+0

¿por qué? Una respuesta increíble, acabo de empezar a aprender wpf también con un programa de herramienta de cambio de nombre que estoy creando y parece que tienes que tener muchos pacientes aprendiéndolo ... – Chopnut

Cuestiones relacionadas