Jak utworzyć powiązanie z metodą obiektów w tym scenariuszu w 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>
Tutaj chcę powiązać się z GetChildren
metodą na każdym RootObject
drzewie.
EDYCJAObjectDataProvider
Wydaje się, że powiązanie z elementem an nie działa, ponieważ wiążę się z listą elementów i ObjectDataProvider
potrzebuje albo statycznej metody, albo tworzy własną instancję i używa jej.
Na przykład, używając odpowiedzi Matta, otrzymuję:
Błąd System.Windows.Data: 33: ObjectDataProvider nie może utworzyć obiektu; Type = 'RootObject'; Błąd = „Nieprawidłowe parametry konstruktora”.
Błąd System.Windows.Data: 34: ObjectDataProvider: Błąd podczas próby wywołania metody dla typu; Method = 'GetChildren'; Type = 'RootObject'; Error = „Określony członek nie może zostać wywołany w miejscu docelowym.” TargetException: „System.Reflection.TargetException: metoda niestatyczna wymaga celu.
źródło
Odpowiedzi:
Innym podejściem, które może zadziałać, jest utworzenie niestandardowego,
IValueConverter
który przyjmuje nazwę metody jako parametr, tak aby był używany w następujący sposób:Ten konwerter znalazłby i wywołałby metodę przy użyciu odbicia. To wymaga, aby metoda nie miała żadnych argumentów.
Oto przykład źródła takiego konwertera:
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."); } }
I odpowiedni test jednostkowy:
[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)); }
Zauważ, że ten konwerter nie wymusza tego
targetType
parametru.źródło
Nie jestem pewien, jak dobrze zadziała w Twoim scenariuszu, ale możesz użyć tej
MethodName
właściwości,ObjectDataProvider
aby wywołać określoną metodę (z określonymi parametramiMethodParameters
właściwości) w celu pobrania danych.Oto fragment pobrany bezpośrednio ze strony 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>
Więc to
ObjectDataProvider
jest wywołanieConvertTemp
metody na instancjiTemperatureScale
klasy, przekazując dwa parametry (0
iTempType.Celsius
).źródło
Czy musisz wiązać się z metodą?
Czy możesz powiązać się z właściwością, która pobiera metodę?
public ObservableCollection<ChildObject> Children { get { return GetChildren(); } }
źródło
O ile nie możesz dodać właściwości, aby wywołać metodę (lub utworzyć klasę opakowania, która dodaje tę właściwość), jedynym znanym mi sposobem jest użycie ValueConverter.
źródło
ObjectDataProvider ma również właściwość ObjectInstance, której można użyć zamiast ObjectType
źródło
Możesz użyć
System.ComponentModel
do dynamicznego definiowania właściwości dla typu (nie są one częścią skompilowanych metadanych). Użyłem tego podejścia w WPF, aby włączyć powiązanie z typem, który przechowywał swoje wartości w polach, ponieważ powiązanie z polami nie jest możliwe.Te
ICustomTypeDescriptor
iTypeDescriptionProvider
typy mogą pozwala osiągnąć to, co chcesz. Zgodnie z tym artykułem :Sam nie próbowałem tego podejścia, ale mam nadzieję, że będzie to pomocne w Twoim przypadku.
źródło
Aby powiązać z metodą obiektu w scenariuszu WPF, można powiązać z właściwością, która zwraca delegata.
źródło