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


90

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항목 목록에 바인딩하기 때문에 EDIT Binding이 작동하지 않는 것 같습니다 ObjectDataProvider. 정적 메서드 가 필요하거나 자체 인스턴스를 만들고 사용합니다.

예를 들어 Matt의 대답을 사용하면 다음과 같은 결과를 얻습니다.

System.Windows.Data 오류 : 33 : ObjectDataProvider가 개체를 만들 수 없습니다. Type = 'RootObject'; Error = '잘못된 생성자 매개 변수.'

System.Windows.Data 오류 : 34 : ObjectDataProvider : 형식에서 메서드를 호출하는 데 실패했습니다. Method = 'GetChildren'; Type = 'RootObject'; 오류 = '지정된 구성원은 대상에서 호출 할 수 없습니다.' TargetException : 'System.Reflection.TargetException : 비 정적 메서드에는 대상이 필요합니다.


그래, 당신 말이 맞아. ObjectDataProvider에는 ObjectInstance 속성 (특정 인스턴스에 대한 메서드 호출)이 있지만 종속성 속성이 아니라고 생각하므로 바인딩 할 수 없습니다 (AFAIK).
Matt Hamilton

1
예, ObjectInstance에 바인딩하려고 시도했지만 종속성 속성이 아님을 알았습니다.
Cameron MacFarland

어쨌든 나는 당신의 업데이트에 약간의 맥락을 제공하고 비슷한 문제 로이 질문을 찾는 다른 사람을 돕기 위해 내 대답을 남겨 둘 것입니다.
Matt Hamilton

실제로 ObjectInstance에 바인딩해야합니까? ... 대신 자신의 변화 이벤트 처리를 만들 수 있도록 가정 (이 변경됩니다) 및 코드에서 ObjectDataProvider를 업데이트
팀 로벨 - 스미스

1
사실 1 년 후 소스 코드로 내 대답을 업데이트했습니다.
Drew Noakes

답변:


71

작동 할 수있는 또 다른 접근 방식 IValueConverter은 메서드 이름을 매개 변수 로 사용하는 사용자 지정을 만들어 다음 과 같이 사용하는 것입니다.

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매개 변수를 적용하지 않습니다 .


6
흠, ... 해킹처럼 보이지만 이것이 유일한 방법이라고 생각하기 시작했습니다. 정말 가장 쉬울 것입니다!
EightyOne Unite

25

시나리오에서 얼마나 잘 작동할지 확실하지 않지만의 MethodName속성을 사용하여 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발신 사용자들은 ConvertTemp의 인스턴스에 대한 방법 TemperatureScale(두 개의 매개 변수를 전달 클래스를 0하고 TempType.Celsius).


11

메서드에 바인딩해야합니까?

getter가 메소드 인 속성에 바인딩 할 수 있습니까?

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

2
나는 Cameron의 코멘트를 그가 속성을 추가 할 수없는 유형에 바인딩하고 있다는 것을 의미합니다.
Drew Noakes

2
메서드가 잠재적으로 오래 실행될 수있는 경우 메서드 esp를 호출하는 속성에 대한 바인딩을 피해야합니다. 이러한 메서드를 사용하는 것은 코드 소비자가 속성이 지역 변수에만 액세스하기를 기대하기 때문에 좋은 디자인이 아닙니다.
markmnl 2010

@markmnl 그래서 기능에 직접 바인딩하는 요점은 무엇입니까? 그래서 OP의 질문이 귀하의 경우에 의미가 없습니까?
Teoman shipahi

4

메서드를 호출하는 속성을 추가하거나 해당 속성을 추가하는 래퍼 클래스를 만들 수 없다면 내가 아는 유일한 방법은 ValueConverter를 사용하는 것입니다.



3

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

ICustomTypeDescriptorTypeDescriptionProvider유형은 당신이 원하는 것을 달성 할 수 있습니다. 이 기사 에 따르면 :

TypeDescriptionProvider구현하는 별도의 클래스를 작성한 ICustomTypeDescriptor다음이 클래스를 다른 유형에 대한 설명 제공자로 등록 할 수 있습니다.

이 접근 방식을 직접 시도한 적은 없지만 귀하의 경우에 도움이 되었기를 바랍니다.


0

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.