programing

WPF에서 메서드에 바인딩하시겠습니까?

iphone6s 2023. 5. 7. 11:15
반응형

WPF에서 메서드에 바인딩하시겠습니까?

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>

여기서 나는 다음에 바인딩합니다.GetChildren각각의 방법RootObject나무의

에 대한 바인딩 편집ObjectDataProvider제가 아이템 목록에 바인딩되어 있기 때문에 작동하지 않는 것 같고, 그리고.ObjectDataProvider정적 메서드가 필요하거나 고유한 인스턴스를 생성하여 사용합니다.

예를 들어 Matt의 답변을 사용하면 다음과 같이 얻을 수 있습니다.

시스템. 윈도우.데이터 오류: 33 : ObjectDataProvider가 개체를 만들 수 없습니다.유형='RootObject'; 오류='생성자에 대한 매개 변수가 잘못되었습니다.'

시스템. 윈도우.데이터 오류: 34 : ObjectDataProvider:메서드='GetChildren', 유형='RootObject', 오류=' 유형에서 메서드를 호출하지 못했습니다.지정한 구성원을 대상에서 호출할 수 없습니다.'대상 예외: '시스템.반사.대상 예외: 정적 메서드가 아닌 메서드에는 대상이 필요합니다.

메서드 이름을 매개 변수로 사용하는 사용자 정의를 생성하여 다음과 같이 사용할 수도 있습니다.

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

이 변환기는 반사를 사용하여 메소드를 찾아 호출합니다.메서드에 인수가 없어야 합니다.

다음은 이러한 변환기 소스의 예입니다.

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.");
    }
}

해당 장치 테스트:

[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));
}

이 변환기는 다음을 수행하지 않습니다.targetType매개 변수

시나리오에서 얼마나 잘 작동할지 확실하지 않지만 속성을 사용할 수 있습니다.ObjectDataProvider특정 메소드(사용자의 특정 매개 변수 포함)를 호출합니다.MethodParameters데이터를 검색합니다.

다음은 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>

그래서 그것은ObjectDataProvider그것은 a야.ConvertTemp의 예에 의한 방법.TemperatureScale클래스, 두 매개 변수 전달(0그리고.TempType.Celsius).

당신은 그 방법을 고수해야 합니까?

당신은 그 방법이 더 나은 부동산에 묶을 수 있습니까?

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

메서드를 호출할 속성을 추가할 수 있는 경우(또는 해당 속성을 추가하는 래퍼 클래스를 만들 수 있는 경우)를 제외하고 내가 아는 유일한 방법은 ValueConverter를 사용하는 것입니다.

ObjectDataProvider에는 ObjectType 대신 사용할 수 있는 ObjectInstance 속성도 있습니다.

사용할 수 있습니다.System.ComponentModel컴파일된 메타데이터의 일부가 아닌 유형의 속성을 동적으로 정의합니다.필드에 바인딩할 수 없기 때문에 필드에 값을 저장한 유형에 바인딩할 수 있도록 WPF에서 이 접근 방식을 사용했습니다.

및 유형을 사용하면 원하는 것을 달성할 수 있습니다. 기사에 따르면:

TypeDescriptionProvider 를구는별클작수있성다습니할를래스를 할 수 있습니다.ICustomTypeDescriptor그런 다음 이 클래스를 다른 형식에 대한 설명 제공자로 등록합니다.

제가 직접 이런 방법을 시도해 본 적은 없지만, 당신의 경우 도움이 되길 바랍니다.

WPF 시나리오에서 개체의 메서드에 바인딩하려면 대리자를 반환하는 속성에 바인딩할 수 있습니다.

드류 노익스의 대답과 동일하지만 확장 방법을 사용할 수 있습니다.

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, Type.EmptyTypes);
        if (methodInfo == null)
        {
            methodInfo = GetExtensionMethod(value.GetType(), methodName);
            if (methodInfo == null) return value;
            return methodInfo.Invoke(null, new[] { value });
        }
        return methodInfo.Invoke(value, Array.Empty<object>());
    }

    static MethodInfo? GetExtensionMethod(Type extendedType, string methodName)
    {
        var method = Assembly.GetExecutingAssembly()
            .GetTypes()
            .Where(type => !type.IsGenericType && !type.IsNested)
            .SelectMany(type => type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic), (_, method) => method)
            .Where(m => m.IsDefined(typeof(ExtensionAttribute), false))
            .Where(m => m.GetParameters()[0].ParameterType == extendedType)
            .FirstOrDefault(m => m.Name == methodName);
        return method;
    }

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

언급URL : https://stackoverflow.com/questions/502250/bind-to-a-method-in-wpf

반응형