2012-04-26 20 views
5

Estoy trabajando en una extensión de marcado personalizada en la que necesito un parámetro que no sea de cadena de XAML para construir el nuevo objeto. ¿Es posible usar un enlace de parámetro que no sea de cadena en un campo en el ámbito del contexto de datos?MarkupExtension con parámetros de enlace

En otras palabras, ¿cómo puedo hacer algo como esto?

<ListBox ItemsSource="{Binding Source={local:MyMarkupExtension {x:Type Button},IncludeMethods={Binding Source=CustomerObject.IsProblematic}}}" /> 

donde IncludeMethods=CustomerObject.IsProblematic me da este error: La unión no puede ajustarse en la propiedad '' IncludeMethods del tipo 'TypeDescriptorExtension'. Un 'Enlace' solo se puede establecer en una DependencyProperty de un DependencyObject.

¿Alguien me puede ayudar?

gracias

Respuesta

9

Un 'vinculante' sólo puede ajustarse en un DependencyProperty de DependencyObject - es cierto. El problema es que la clase MarkupExtension no se deriva de DependencyObject, por eso no es posible establecer un enlace en sus propiedades.

[EDIT]

Solución está utilizando ValueConverters. Otra solución es cambiar el lenguaje C# para permitir herencia múltiple. Por cierto, en Silverlight MarkupExtension implementa la interfaz IMarkupExtension, así que traté de implementarlo en mi extensión personalizada y derivarlo de DependecyObject, agregué DependencyProperty allí y establecí el enlace. No se bloquea, pero el enlace se establece en realidad después de llamar al ProvideValue(). Entonces, incluso en Silverlight no hay solución (o es difícil, ver el enlace proporcionado en Klaus78's answer). En WPF MarkupExtension no implementa ninguna interfaz, por lo que no puede vincularse a sus propiedades.

+0

¿alguien puede sugerir una solución? – user1351709

+0

por favor vea mi edición – EvAlex

+17

Cambiar el lenguaje C# para permitir herencia múltiple no es exactamente lo que llamaría una "solución";) –

0

Este enlace es informativo sobre

Custom Markup Extension with bindable properties

EDITAR Alguien me hace notar que esto sólo funciona para Silverlight, ya que en WPF MarkupExtension no implementa la interfaz IMarkupExtension. (Gracias EvAlex)

+0

Funciona solo para Silverlight, porque en WPF MarkupExtension no implementa la interfaz IMarkupExtension – EvAlex

-1

Encontré una solución para este problema.
La idea principal es definir la propiedad adjunta para cada parámetro que requiera el enlace.

public class MarkupExtensionWithBindableParam : MarkupExtension 
{ 
    public BindingBase Param1 { get; set; } // its necessary to set parameter type as BindingBase to avoid exception that binding can't be used with non DependencyProperty 

    public override object ProvideValue(IServiceProvider serviceProvider) 
    { 
     IProvideValueTarget target = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget; 
     DependencyObject targetObject; 
     DependencyProperty targetProperty; 

     if (target != null && target.TargetObject is DependencyObject && target.TargetProperty is DependencyProperty) 
     { 
      targetObject = (DependencyObject)target.TargetObject; 
      targetProperty = (DependencyProperty)target.TargetProperty; 
     } 
     else 
     { 
      return this; // magic 
     } 

     // Bind the Param1 to attached property Param1BindingSinkProperty 
     BindingOperations.SetBinding(targetObject, MarkupExtensionWithBindableParam.Param1BindingSinkProperty, Param1); 

     // Now you can use Param1 

     // Param1 direct access example: 
     object param1Value = targetObject.GetValue(Param1BindingSinkProperty); 

     // Param1 use in binding example: 
     var param1InnerBinding = new Binding() { Source = targetObject, Path = new PropertyPath("(0).SomeInnerProperty", Param1BindingSinkProperty) }); // binding to Param1.SomeInnerProperty 
     return param1InnerBinding.ProvideValue(serviceProvider); // return binding to Param1.SomeInnerProperty 
    } 

    private static DependencyProperty Param1BindingSinkProperty = DependencyProperty.RegisterAttached("Param1BindingSink", typeof(object)// set the desired type of Param1 for at least runtime type safety check 
         , typeof(MarkupExtensionWithBindableParam), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits)); 
} 

El uso es sencillo:

<TextBlock Text={local:MarkupExtensionWithBindableParam Param1={Binding Path="SomePathToParam1"}}/> 
+0

Hay un problema con el ejemplo * Usage *. ¿El marcado no debe estar entre comillas? – OmegaMan

+1

no parece funcionar; param1Value siempre es nulo – esskar