2010-04-09 3 views
105

У меня ситуация, в которой мне нужно, чтобы показать целое значение, связанное со свойством в моем контексте данных, после ввода его с помощью два отдельных преобразований:Есть ли способ связать несколько преобразователей значений в XAML?

  1. Обратного значения в пределах диапазона (например, диапазон составляет от 1 до 100, значение DataContext 90, пользователь видит значение 10)
  2. преобразовать число в строку

я понимаю, что я мог сделать оба шага, создавая свой собственный конвертер (который реализует IValueConverter). Однако у меня уже есть отдельный конвертер значений, который делает только первый шаг, а второй шаг - Int32Converter.

Есть ли способ связать эти два существующих класса в XAML, не создавая дополнительный класс, который их объединяет?

Если мне нужно прояснить это, сообщите мне. :)

Спасибо.

ответ

50

Найдено именно то, что я искал, любезно Джош Смит: Piping Value Converters(archive.org link).

Он определяет класс ValueConverterGroup, использование которого в XAML происходит именно так, как я надеялся. Вот пример:

<!-- 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> 

Отличный материал. Спасибо, Джош. :)

+1

В этом решении каждый конвертер должен иметь дело только с одним типом (он должен быть объявлен в атрибуте single-ValueConversion). Решение @Town также может справиться с мультиконвертерами. –

+5

, пожалуйста, опубликуйте реализацию; в противном случае linkrot –

4

Да, есть способы конвертировать конвертеры, но это не выглядит красиво, и вам здесь не нужно. Если вам когда-нибудь понадобится это, спросите себя, действительно ли это путь? Простой всегда работает лучше, даже если вам нужно написать собственный конвертер.

В вашем конкретном случае все, что вам нужно сделать, - это преобразовать преобразованное значение в строку. StringFormat Недвижимость на Binding является вашим другом здесь.

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

будет StringFormat работу в TwoWay? – diimdeep

+2

Если вы сильно используете привязки, запись пользовательского конвертера в цепные преобразователи заканчивается множеством немых конвертеров для всех видов конфигураций. В этом случае принятый ответ - прекрасное решение. –

165

Я использовал this method от Gareth Evans в моем проекте Silverlight.

Вот моя реализация этого:

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 будет возвращать this.Reverse (). Агрегат (значение, (текущий, конвертер) => converter.ConvertBack (текущий, targetType, параметр, культура)); ' –

+5

@DLeh Это не очень элегантный как это не работает. Он предоставляет все конвертеры с конечным целевым типом вместо правильного целевого типа ... –

+0

Это работает и в UWP, yay! –

0

Town's implementation из Gareth Evans's Silverlight project велик, однако он не поддерживает различные параметры преобразователя.

Я изменил его, чтобы вы могли предоставить параметры, разделенные запятой (если вы не избежите их, конечно).

Преобразователь:

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 не реализована здесь, см мой Gist для обновленной версии.

Реализация:

<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> 
Смежные вопросы