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.