2009-04-22 5 views
6

Estoy intentando vincular una propiedad TextBlock's Text de una manera muy dinámica. Necesito obtener el Camino de un objeto subyacente.¿Cómo vinculo la propiedad Binding.Path con los datos subyacentes?

Aquí está la DataTemplate:

<DataTemplate DataType={x:Type local:DummyClass}> 
    <TextBlock Text={Binding Path=???} /> 
</DataTemplate> 

El objeto DummyClass tiene una propiedad denominada "FieldValuePath" - el camino que hay que poner en el ??? es.

La idea detrás de esto es que se supone que la plantilla de datos es una GUI para ver/editar cualquier propiedad de cualquier objeto. Por lo tanto, es preferible poder declarar XAML, lo que vincularía algunos controles (cuadros de texto, bloques de texto, separadores de fechas, etc.) a una propiedad determinada.

Quizás alguien tenga alguna sugerencia sobre cómo implementar tal cosa?

Respuesta

7

Si crea el enlace en el código de detrás, puede hacer que funcione. Por ejemplo, un simple código generado es vinculante:

Binding binding = new Binding("BindingPath"); 
binding.Mode = BindingMode.TwoWay; 
BindingOperations.SetBinding(textBoxName, TextBox.TextProperty, binding); 

Puesto que la trayectoria de esta unión ("BindingPath") es una cadena, esa cadena podría venir de cualquier objeto disponible.

Sin embargo, tendrá que enganchar en la creación de sus elementos de datos para establecer estos enlaces.


Una posibilidad adicional sobre la base de sus comentarios:

This blog post describe una manera de crear una clase personalizada de unión heredando de MarkupExtension. Es posible que pueda utilizar esto como punto de partida para incluir mi sugerencia en un marcado xaml reutilizable para su caso especial de encuadernación.


Más pensamientos:

Bueno, esto fue un problema interesante, así que decidimos pasar un poco de tiempo de ver si podía llegar a una solución de trabajo. Me disculpo de antemano por la longitud de los siguientes ejemplos de código ...

Basando mi solución en el blog he vinculado a lo anterior creado esta clase:

public class IndirectBinder : MarkupExtension 
    { 
     public string IndirectProperty { get; set; } 

     public override object ProvideValue(IServiceProvider serviceProvider) 
     { 
      //try to get bound items for our custom work 
      DependencyObject targetObject; 
      DependencyProperty targetProperty; 
      bool status = TryGetTargetItems(serviceProvider, out targetObject, out targetProperty); 

      if (status) 
      { 
       Control targetControl = targetObject as Control; 
       if (targetControl == null) return null; 

       //Find the object to take the binding from 
       object dataContext = targetControl.DataContext; 
       if (dataContext == null) return null; 

       //Reflect out the indirect property and get the value 
       PropertyInfo pi = dataContext.GetType().GetProperty(IndirectProperty); 
       if (pi == null) return null; 

       string realProperty = pi.GetValue(dataContext, null) as string; 
       if (realProperty == null) return null; 

       //Create the binding against the inner property 
       Binding binding = new Binding(realProperty); 
       binding.Mode = BindingMode.TwoWay; 
       BindingOperations.SetBinding(targetObject, targetProperty, binding); 

       //Return the initial value of the binding 
       PropertyInfo realPi = dataContext.GetType().GetProperty(realProperty); 
       if (realPi == null) return null; 

       return realPi.GetValue(dataContext, null); 

      } 

      return null; 

     } 

     protected virtual bool TryGetTargetItems(IServiceProvider provider, out DependencyObject target, out DependencyProperty dp) 
     { 
      target = null; 
      dp = null; 
      if (provider == null) return false; 

      //create a binding and assign it to the target 
      IProvideValueTarget service = (IProvideValueTarget)provider.GetService(typeof(IProvideValueTarget)); 
      if (service == null) return false; 

      //we need dependency objects/properties 
      target = service.TargetObject as DependencyObject; 
      dp = service.TargetProperty as DependencyProperty; 
      return target != null && dp != null; 
     } 

Se puede utilizar esta nueva marcación con el XAML siguiente:

<TextBox Text="{local:IndirectBinder IndirectProperty=FieldValuePath}"/> 

Dónde cuadro de texto puede ser cualquier clase que hereda de control y texto puede ser cualquier propiedad de dependencia.

Obviamente si necesita exponer cualquiera de las otras opciones de enlace de datos (como el enlace de una o dos vías), tendrá que agregar más propiedades a la clase.

Si bien esta es una solución complicada, una de las ventajas que tiene sobre el uso de un convertidor es que la vinculación que finalmente se crea va en contra de la propiedad interior real en lugar del objeto. Esto significa que reacciona correctamente a los eventos PropertyChanged.

+0

bien, este es un enfoque que podría funcionar, pero que realmente me gustaría ser capaz de crear enlaces en XAML, porque estoy planeando escribir tienen diferentes propiedades de unión en función del estado de los datos subyacentes. Pero posiblemente i de hecho podría tratar de escribir todo esto lógica en el código subyacente ... – arconaut

+0

y, además, no sólo TextBlock que tengo la intención de especificar unión para. Se supone que es un editor/visor para cualquier propiedad en cualquier objeto. Creo que debería agregarlo a la publicación principal. – arconaut

+0

gracias por la respuesta, y gracias por el enlace. Voy a probar esto – arconaut

-1
<DataTemplate DataType={x:Type local:DummyClass}> 
    <TextBlock Text={Binding Path=FieldValuePath} /> 
</DataTemplate> 

Debe ser el método correcto.Si está escuchando a los cambios en FieldValuePath, tendrá que asegurarse de que DummyClass hereda de INotifyPropertyChanged y que el evento ha cambiado propiedad se activa cuando cambia la FieldValuePath.

+0

lo siento, pero esto establecería que el texto sea igual al valor de FieldValuePath. Así que si usted tiene dummyObject.FieldValuePath == "Propiedad1" obtendrá TextBlock.Text == "Propiedad1" – arconaut

+0

En ese caso, se declaró todas sus propiedades como DependencyProperties? Debería poder vincularse con la propiedad si ese es el caso. Esto podría ayudar ... http://geekswithblogs.net/thibbard/archive/2008/04/22/wpf-custom-control-dependency-property-gotcha.aspx –

2

yo recomendaría usar un convertidor:

<DataTemplate DataType={x:Type local:DummyClass}> 
    <TextBlock Text={Binding Converter={StaticResource PropertyNameToValueConverter, ConverterParameter=FieldValuePath}} /> 
</DataTemplate> 

El convertidor conseguiría la clase y el nombre de la propiedad y de allí se devolvería el valor utilizando la reflexión.

+0

Pero volvería sólo una vez. – arconaut

Cuestiones relacionadas