XAML'de birden çok değer dönüştürücüyü zincirlemenin bir yolu var mı?


123

Veri bağlamımdaki bir mülke bağlı bir tamsayı değerini iki ayrı dönüştürmeden sonra göstermem gereken bir durum var:

  1. Bir aralıktaki değeri ters çevirin (ör. Aralık 1 ila 100; veri bağlamındaki değer 90; kullanıcı 10 değerini görür)
  2. sayıyı bir dizeye dönüştür

Kendi dönüştürücümü (IValueConverter uygulayan) oluşturarak her iki adımı da yapabileceğimi fark ettim. Bununla birlikte, yalnızca ilk adımı gerçekleştiren ayrı bir değer dönüştürücüm var ve ikinci adım Int32Converter tarafından kapsanmaktadır.

Bir şekilde ben kutu zinciri bu iki varolan sınıfları var mı XAML bir başka sınıf olduğunu agrega onları oluşturmak zorunda kalmadan?

Bunlardan herhangi birini açıklamam gerekirse, lütfen bana bildirin. :)

Teşekkürler.

Yanıtlar:


198

Silverlight projemde bu yöntemi Gareth Evans tarafından kullandım .

İşte benim uygulamam:

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
}

Daha sonra XAML'de şu şekilde kullanılabilir:

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

3
En iyisi, bir ConvertBack uygulaması için koleksiyonun bir kopyasını alıp tersine çevirmek ve ardından bunun üzerinden Toplamak mı? Yani ConvertBackreturn this.Reverse<IValueConverter>().Aggregate(value, (current, converter) => converter.ConvertBack(current, targetType, parameter, culture));
Nick Udell

5
@DLeh Bu işe yaramadığı için gerçekten şık değil. Tüm dönüştürücülere doğru hedef türü yerine nihai hedef türü sağlar ...
Aleksandar Toplek

Bunu bir MultiValueConverter ile ilk Dönüştürücü olarak nasıl kullanabilirim?
LightMonk

1
@Town Bir meslektaşım bu soruyu buldu ve nostalji aşkına tekrar bakmamı sağladı. Sadece, hak ettiğiniz krediyi almadığınızı fark ettim ( kendi cevabımı kabul ettim !), Bu yüzden cevabınızı şimdi kabul edildi olarak işaretledim. Sadece 9 yıl kadar geç ...: facepalm:
Mal Ross

@MalRoss Haha! Teşekkür ederim! Hala yararlı olduğunu duyduğuma sevindim, Silverlight'a yaklaşık 8 yıldır dokunmadım ve yine de en popüler cevabım bu :)
Kasaba

54

Tam olarak aradığımı buldum, Josh Smith'in izniyle: Piping Value Converters (archive.org bağlantısı) .

ValueConverterGroupXAML'de kullanımı tam olarak umduğum gibi olan bir sınıf tanımlıyor . İşte bir örnek:

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

Harika şeyler. Teşekkürler Josh. :)


2
Bu çözümde, her dönüştürücü yalnızca bir türle ilgilenmelidir (tek-ValueConversion-özniteliğinde bildirilmelidir). @Town çözümü çoklu dönüştürücülerle de baş edebilir.
Y. Shoham

9
lütfen uygulamayı gönderin; aksi takdirde, linkrot
Jake Berger

9

Town'un uygulama arasında Gareth Evans'ın Silverlight projesi farklı çevirici parametrelerini desteklemiyorsa ancak harika.

Parametreleri virgülle ayrılmış olarak sağlayabilmeniz için değiştirdim (tabii bunlardan kaçmadığınız sürece).

Dönüştürücü:

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

Not: ConvertBack burada uygulanmamaktadır , tam sürüm için Gist'ime bakın .

Uygulama:

<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

Evet, dönüştürücüyü zincirlemenin yolları var ama güzel görünmüyor ve burada ona ihtiyacınız yok. Buna hiç ihtiyaç duyarsanız, kendinize sorun, gerçekten gidilecek yol bu mu? Kendi dönüştürücünüzü yazmanız gerekse bile basit her zaman daha iyi çalışır.

Özel durumunuzda, yapmanız gereken tek şey, dönüştürülmüş bir değeri bir dizeye biçimlendirmektir. StringFormatmülkiyet Bindingburada arkadaşınızdır.

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

5
Bağlamaları yoğun bir şekilde kullanırsanız, zincir dönüştürücülere özel dönüştürücü yazmak, her tür yapılandırma için tonlarca aptal dönüştürücü ile sonuçlanır. Bu durumda kabul edilen cevap harika bir çözümdür.
Jacek Gorgoń

0

İşte çoklu bağlamayı desteklemek için Kasabanın yanıtının küçük bir uzantısı :

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
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.