way two que property data context wpf binding

two - wpf binding types



Principiante-confundido sobre el enlace y los recursos en WPF (2)

Estoy tratando de aprender WPF pero me resulta muy difícil entender los enlaces, los "recursos" y la creación de objetos. Mi experiencia es en C ++ / MFC y C # -Winforms.

Mis preguntas:

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

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

  3. Para vincular las dos preguntas anteriores: cuando defino una instancia de objeto en la sección Recursos y luego la referenciado desde un enlace StaticResource, ¿cuándo se crea una instancia exacta? MSDN dice (en "Cómo: Hacer que los datos estén disponibles para el enlace en XAML"):

Una forma de hacer que el objeto esté disponible para el enlace es definirlo como un recurso

Sin embargo, esto no está muy claro. ¿Qué significan disponibles? ¿Significan creados? ¿Significan conectados al subsistema de enlace? ¿Y cuándo exactamente se crea ese objeto? De jugar con un simple ejemplo, 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 de karmicpuppet a continuación, todavía estoy confundido en cuanto a cómo está conectado a Binding. Supongamos que tengo en mis recursos:

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

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

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

1) ¿Qué hace esto? ¿Sigue los mismos pasos: buscar el recurso y luego aplicarlo a la propiedad Texto? ¿Se crea el objeto MyPerson 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 vincularlo directamente como hiciste anteriormente con myBrush? ¿Por qué no puedo hacer algo como esto?

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

¿Es solo una falta de visión por parte del marco? Creo que me estoy perdiendo mucho aquí, pero parece que no puedo entender qué ...

3) Intenté usar DynamicResource, pero estoy muy confundido acerca de cada paso que di. a) Se agregó un DependencyObject con un DependencyProperty por encima de mi clase de Windows única en el código (¿es necesario este 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) Se agregó una instancia de la misma a los recursos de Windows (¿es necesario con DynamicResource? MSDN parece decir que no, pero si es así, no puedo averiguar cómo hacer el siguiente paso en XAML)

c) Probé ambos:

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

Lo que me dio una excepción, y

Text="{DynamicResource HeaderText}"

Pero no pude entender dónde colocar el camino a la propiedad Encabezado.

Este es mi quinto intento, más o menos, de juguetear con WPF últimamente, y cada vez me desconciertan 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.


Piénselo de esta manera: todos los FrameworkElements (Windows, botones, otros controles, etc.), así como el objeto Aplicación, contienen un Diccionario de recursos. Cuando 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()); } }

Puedes poner todo tipo de objetos como Recursos. Cualquier cosa que desee reutilizar a lo largo de su aplicación, puede definirla como un Recurso.

Ahora, cuando use un "{StaticResource}" como sigue:

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

Esto es como decirle a WPF que busque el recurso correspondiente "myBrush" y lo aplique a la propiedad Fondo. Lo que sucederá es que WPF buscará primero el recurso en el diccionario de recursos de Button y, si no lo encuentra, buscará en su padre, luego en su padre, 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 este enlace .

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

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

y lo usé como:

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

En este caso, lo que sucederá es algo como esto:

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

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

Eso es lo básico. Espero que encuentres esto útil


Primero, un comentario general:

WPF es difícil de aprender. Es difícil de aprender porque hay varios conceptos diferentes, fundamentalmente nuevos, que debes entender al mismo tiempo. La lucha que estás teniendo ahora mismo es que estás tratando de aprender al menos tres cosas diferentes a la vez:

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

Algo como esto:

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

está involucrando (al menos) tres tecnologías muy diferentes al mismo tiempo. Todas estas tecnologías están diseñadas para ser lo más flexibles posible, lo que solo las hace más confusas para el principiante. La idea de que una fuente de enlace puede ser casi cualquier cosa: 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: en principio, lo suficientemente simple como para entender, pero un poco desconcertante cuando empiezas 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: una vez más, su concepto es bastante simple, pero es fácil perder el hilo cuando intenta averiguar 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 entiendas muchas cosas antes de poder expresarlo en XAML.

La única solución es ser paciente y asegurarse de que comprende las cosas en el nivel más bajo posible. Cuando veas esto:

{StaticResource MyPerson}

debería poder pensar, "Eso va a invocar el controlador de extensión de marcado StaticResource , que recupera un objeto de un diccionario de recursos utilizando la clave MyPerson cuando se deserializa el XAML.

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

Para abordar un par de problemas que karmicpuppet no hizo:

De mi experiencia en MFC [recursos] fueron íconos, cadenas, etc.

Eso no ha cambiado. Aún puede crear archivos de recursos en WPF y cargarlos en objetos en tiempo de ejecución. Hay muchas formas 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 no conozco.

Los recursos disponibles para FrameworkElement a través de sus diccionarios de recursos son una cosa diferente. Especie de. Aquí hay un ejemplo:

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

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

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

En la práctica, esto no es tan confuso como cuando aprendes WPF por primera vez. Nunca obtengo los recursos que carga ResourceManager y los recursos almacenados en los diccionarios de recursos mezclados.

¿Y cuándo exactamente se crea ese objeto?

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

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

crea una instancia de un nuevo objeto Person y lo agrega al diccionario de recursos de Window con una clave de MyPerson . Es exactamente equivalente a hacer esto en el código detrás de la Window :

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

Entonces, ¿por qué no lo haces solo en código detrás? 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 define tanto en XAML como en código subyacente, debe buscar en dos lugares.

Segundo, el IDE conoce los recursos que define en XAML. Si escribes

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

en su XAML, el IDE le informará si no ha definido, en algún lugar de la jerarquía de los diccionarios de recursos, un recurso cuya clave es MyPerson . Pero no conoce 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 reportará como un problema.