XAML에서 여러 값 변환기를 연결하는 방법이 있습니까?


123

두 개의 개별 변환을 통해 데이터 컨텍스트의 속성에 바인딩 된 정수 값을 표시해야하는 상황이 있습니다.

  1. 범위 내에서 값 반전 (예 : 범위는 1에서 100, 데이터 컨텍스트의 값은 90, 사용자는 10의 값을 봅니다)
  2. 숫자를 문자열로 변환

IValueConverter를 구현하는 자체 변환기를 만들어 두 단계를 모두 수행 할 수 있다는 것을 알고 있습니다. 그러나 이미 첫 번째 단계 만 수행하는 별도의 값 변환기가 있으며 두 번째 단계는 Int32Converter에서 다룹니다.

이 두 개의 기존 클래스를 집계하는 추가 클래스를 만들지 않고도 XAML에서 연결할 수있는 방법이 있습니까?

이에 대해 명확히해야하는 경우 알려 주시기 바랍니다. :)

감사.

답변:


198

Silverlight 프로젝트에서 Gareth Evans 가이 방법 을 사용 했습니다 .

내 구현은 다음과 같습니다.

public class ValueConverterGroup : List<IValueConverter>, IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return this.Aggregate(value, (current, converter) => converter.Convert(current, targetType, parameter, culture));
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}

다음과 같이 XAML에서 사용할 수 있습니다.

<c:ValueConverterGroup x:Key="InvertAndVisibilitate">
   <c:BooleanInverterConverter/>
   <c:BooleanToVisibilityConverter/>
</c:ValueConverterGroup>

3
ConvertBack의 구현이 컬렉션의 복사본을 만들고 뒤집은 다음 그 위에 집계하는 것이 가장 좋습니까? 따라서 ConvertBack은 다음과 같습니다return this.Reverse<IValueConverter>().Aggregate(value, (current, converter) => converter.ConvertBack(current, targetType, parameter, culture));
Nick Udell 2014 년

5
@DLeh 작동하지 않기 때문에 정말 우아하지 않습니다. 모든 변환기에 올바른 대상 유형 대신 최종 대상 유형을 제공합니다 ...
Aleksandar Toplek 2015-09-07

MultiValueConverter를 첫 번째 변환기로 사용하려면 어떻게해야합니까?
LightMonk

1
@Town A 동료가 방금이 질문을 찾았고 향수를 불러 일으키기 위해 다시 찾아 보았습니다. 단지, 나는 당신이 당신이받을만한 크레딧을받지 못했다는 것을 알았으므로 (나는 대답을 받아 들였습니다 !), 이제 당신의 대답을 받아 들인 것으로 표시했습니다. 만 9 년 이상 늦게 ... : 마른 세수 :
말 로스

@MalRoss 하하! 감사합니다! 여전히 유용하다는 말을 들으니 다행입니다. 그 중 약 8 년 동안 Silverlight를 건드리지 않았지만 이것이 여전히 가장 인기있는 답변입니다. :)
Town

54

Josh Smith : Piping Value Converters (archive.org 링크)의 호의로 제가 찾고 있던 것을 정확히 찾았습니다 .

그는 ValueConverterGroupXAML에서의 사용이 내가 기대했던 것과 정확히 일치 하는 클래스를 정의합니다 . 예를 들면 다음과 같습니다.

<!-- Converts the Status attribute text to a SolidColorBrush used to draw 
     the output of statusDisplayNameGroup. -->
<local:ValueConverterGroup x:Key="statusForegroundGroup">
  <local:IntegerStringToProcessingStateConverter  />
  <local:ProcessingStateToColorConverter />
  <local:ColorToSolidColorBrushConverter />
</local:ValueConverterGroup> 

좋은 물건. 고마워, 조쉬. :)


2
이 솔루션에서 각 변환기는 하나의 유형 만 처리해야합니다 (단일 ValueConversion-attribute에서 선언되어야 함). @Town 솔루션은 멀티 컨버터에도 대응할 수 있습니다.
Y. Shoham

9
구현을 게시하십시오. 그렇지 않으면, linkrot
제이크 버거

9

Gareth Evans의 Silverlight 프로젝트에 대한 Town의 구현 은 훌륭하지만 다른 변환기 매개 변수를 지원하지 않습니다.

매개 변수를 쉼표로 구분하여 제공 할 수 있도록 수정했습니다 (물론 이스케이프하지 않는 한).

변환기:

public class ValueConverterGroup : List<IValueConverter>, IValueConverter
{
    private string[] _parameters;

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if(parameter != null)
            _parameters = Regex.Split(parameter.ToString(), @"(?<!\\),");

        return (this).Aggregate(value, (current, converter) => converter.Convert(current, targetType, GetParameter(converter), culture));
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    private string GetParameter(IValueConverter converter)
    {
        if (_parameters == null)
            return null;

        var index = IndexOf(converter as IValueConverter);
        string parameter;

        try
        {
            parameter = _parameters[index];
        }

        catch (IndexOutOfRangeException ex)
        {
            parameter = null;
        }

        if (parameter != null)
            parameter = Regex.Unescape(parameter);

        return parameter;
    }
}

참고 : ConvertBack은 여기에서 구현되지 않습니다 . 정식 버전 은 내 요점 을 참조하십시오 .

이행:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:converters="clr-namespace:ATXF.Converters;assembly=ATXF" x:Class="ATXF.TestPage">
  <ResourceDictionary>
    <converters:ValueConverterGroup x:Key="converters">
      <converters:ConverterOne />
      <converters:ConverterTwo />
    </converters:ValueConverterGroup>
  </ResourceDictionary>

  <Label Text="{Binding InitialValue, Converter={StaticResource converters}, ConverterParameter='Parameter1,Parameter2'}" />
</ContentPage>

6

예, 변환기를 연결하는 방법이 있지만 예쁘지 않고 여기에 필요하지 않습니다. 이것을 필요로한다면, 그것이 정말로 갈 길이 냐고 자문 해보십시오. 단순 변환기를 직접 작성해야하는 경우에도 항상 더 잘 작동합니다.

특정 경우에는 변환 된 값을 문자열로 형식화하기 만하면됩니다. StringFormat속성 Binding은 여기 에있는 당신의 친구입니다.

 <TextBlock Text="{Binding Value,Converter={StaticResource myConverter},StringFormat=D}" />

5
바인딩을 많이 사용하는 경우 체인 변환기에 사용자 지정 변환기를 작성하면 모든 종류의 구성에 대해 수많은 바보 변환기가 생성됩니다. 이 경우 허용되는 답변은 훌륭한 솔루션입니다.
Jacek Gorgoń

0

다음은 다중 바인딩을 지원하기 위해 Town의 답변 을 확장 한 것입니다 .

public class ValueConverterGroup : List<IValueConverter>, IValueConverter, IMultiValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return this.Aggregate(value, (current, converter) => converter.Convert(current, targetType, parameter, culture));
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        return Convert(values as object, targetType, parameter, culture);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }

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