2009-02-02 15 views
82

¿Cómo se vincula a un método de objetos en este escenario en WPF?¿Se relaciona con un método en WPF?

public class RootObject 
{ 
    public string Name { get; } 

    public ObservableCollection<ChildObject> GetChildren() {...} 
} 

public class ChildObject 
{ 
    public string Name { get; } 
} 

XAML:

<TreeView ItemsSource="some list of RootObjects"> 
    <TreeView.Resources> 
     <HierarchicalDataTemplate DataType="{x:Type data:RootObject}" 
            ItemsSource="???"> 
      <TextBlock Text="{Binding Path=Name}" /> 
     </HierarchicalDataTemplate> 
     <HierarchicalDataTemplate DataType="{x:Type data:ChildObject}"> 
      <TextBlock Text="{Binding Path=Name}" /> 
     </HierarchicalDataTemplate> 
    </TreeView.Resources> 
</TreeView> 

Aquí quiero enlazar con el método GetChildren en cada RootObject del árbol.

EDITAR unión a un ObjectDataProvider no parece funcionar porque estoy unirse a una lista de elementos, y los ObjectDataProvider necesidades, ya sea un método estático, o crea su propio ejemplo y utiliza eso.

Por ejemplo, usando la respuesta de Matt me sale:

System.Windows.Data Error: 33 : ObjectDataProvider cannot create object; Type='RootObject'; Error='Wrong parameters for constructor.'

System.Windows.Data Error: 34 : ObjectDataProvider: Failure trying to invoke method on type; Method='GetChildren'; Type='RootObject'; Error='The specified member cannot be invoked on target.' TargetException:'System.Reflection.TargetException: Non-static method requires a target.

+0

Sí, tienes razón. ObjectDataProvider tiene una propiedad ObjectInstance (para llamar a su método en una instancia específica) pero no creo que sea una propiedad de dependencia, por lo que no se puede vincular (AFAIK). –

+1

Sí, traté de vincularme a ObjectInstance y descubrí que no es una propiedad de dependencia. –

+0

Dejaré mi respuesta allí de todos modos, tanto para dar a su actualización un contexto como para ayudar a alguien más que encuentre esta pregunta con un problema lo suficientemente similar. –

Respuesta

22
No

seguro de lo bien que va a trabajar en su escenario, pero se puede utilizar la propiedad MethodName en ObjectDataProvider tener que llamar a un método específico (con específica parámetros si la propiedad MethodParameters) recupera sus datos.

He aquí un fragmento tomado directamente de la página de MSDN:

<Window.Resources> 
    <ObjectDataProvider ObjectType="{x:Type local:TemperatureScale}" 
     MethodName="ConvertTemp" x:Key="convertTemp"> 
     <ObjectDataProvider.MethodParameters> 
      <system:Double>0</system:Double> 
      <local:TempType>Celsius</local:TempType> 
     </ObjectDataProvider.MethodParameters> 
    </ObjectDataProvider> 
</Window.Resources> 

Así que eso es un ObjectDataProvider que está llamando a un método "ConvertTemp" en una instancia de una clase "TemperatureScale", pasando dos parámetros (0 y TempType.Celsius) .

+0

He actualizado mi respuesta en función de su respuesta. –

9

¿Tienes que enlazarte al método?

¿Se puede vincular a una propiedad que es getter es el método?

public ObservableCollection<ChildObject> Children 
{ 
    get 
    { 
     return GetChildren(); 
    } 
} 
+0

Tengo que enlazar a un método. –

+2

Considero que el comentario de Cameron significa que es vinculante para un tipo al que no puede agregarle una propiedad. –

+1

Debe evitar el enlace a las propiedades que llaman a los métodos esp si el método podría ser de larga ejecución. Tener tales métodos, sus propiedades no es un buen diseño, ya que un consumidor de código espera que una propiedad solo acceda a una variable local. – markmnl

4

menos que se puede añadir un alojamiento a llamar al método (o crear una clase contenedora que añade que la propiedad) la única forma que conozco es el uso de un ValueConverter.

3

ObjectDataProvider también tiene una propiedad ObjectInstance que se puede utilizar en lugar de ObjectType

3

Puede utilizar System.ComponentModel para definir las propiedades de un tipo de forma dinámica (que no son parte de los metadatos compilado). Utilicé este enfoque en WPF para habilitar el enlace a un tipo que almacenó sus valores en los campos, ya que no es posible vincularlos a los campos.

Los tipos ICustomTypeDescriptor y TypeDescriptionProvider pueden permitirle lograr lo que desea. De acuerdo con this article:

TypeDescriptionProvider allows you to write a separate class that implements ICustomTypeDescriptor and then to register this class as the provider of descriptions for other types.

No he probado este enfoque a mí mismo, pero espero que sea útil en su caso.

59

Otro enfoque que podría funcionar para usted es crear una costumbre IValueConverter que tiene un nombre de método como un parámetro, por lo que sería utilizado como esto:

ItemsSource="{Binding 
    Converter={StaticResource MethodToValueConverter}, 
    ConverterParameter='GetChildren'}" 

Este convertidor encontraría e invocar el método usando la reflexión Esto requiere que el método no tenga ningún argumento.

He aquí un ejemplo de fuente de un convertidor de este tipo:

public sealed class MethodToValueConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     var methodName = parameter as string; 
     if (value==null || methodName==null) 
      return value; 
     var methodInfo = value.GetType().GetMethod(methodName, new Type[0]); 
     if (methodInfo==null) 
      return value; 
     return methodInfo.Invoke(value, new object[0]); 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     throw new NotSupportedException("MethodToValueConverter can only be used for one way conversion."); 
    } 
} 

Y una prueba de unidad correspondiente:

[Test] 
public void Convert() 
{ 
    var converter = new MethodToValueConverter(); 
    Assert.AreEqual("1234", converter.Convert(1234, typeof(string), "ToString", null)); 
    Assert.AreEqual("ABCD", converter.Convert(" ABCD ", typeof(string), "Trim", null)); 

    Assert.IsNull(converter.Convert(null, typeof(string), "ToString", null)); 

    Assert.AreEqual("Pineapple", converter.Convert("Pineapple", typeof(string), "InvalidMethodName", null)); 
} 

Tenga en cuenta que este convertidor no hace cumplir el parámetro targetType.

+4

Hmmm, ... parece un truco, pero estoy empezando a pensar que esta podría ser la única forma. ¡Es seguro que será el más fácil! – Stimul8d

0

Para enlazar al método de un objeto en su escenario WPF, puede enlazar a una propiedad que devuelve un delegado.

Cuestiones relacionadas