Có cách nào để xâu chuỗi nhiều bộ chuyển đổi giá trị trong XAML không?


123

Tôi gặp một tình huống mà tôi cần hiển thị một giá trị số nguyên, liên kết với một thuộc tính trên ngữ cảnh dữ liệu của tôi, sau khi đặt nó qua hai chuyển đổi riêng biệt:

  1. Đảo ngược giá trị trong một phạm vi (ví dụ: phạm vi từ 1 đến 100; giá trị trong văn bản dữ liệu là 90; người dùng thấy giá trị là 10)
  2. chuyển đổi số thành một chuỗi

Tôi nhận ra mình có thể thực hiện cả hai bước bằng cách tạo bộ chuyển đổi của riêng mình (triển khai IValueConverter). Tuy nhiên, tôi đã có một bộ chuyển đổi giá trị riêng biệt chỉ thực hiện bước đầu tiên và bước thứ hai được bao gồm bởi Int32Converter.

Có cách nào để tôi có thể xâu chuỗi hai lớp hiện có này trong XAML mà không cần phải tạo thêm một lớp nữa để tổng hợp chúng không?

Nếu tôi cần làm rõ bất kỳ điều gì trong số này, vui lòng cho tôi biết. :)

Cảm ơn.

Câu trả lời:


198

Tôi đã sử dụng phương pháp này bởi Gareth Evans trong dự án Silverlight của mình.

Đây là cách triển khai của tôi về nó:

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
}

Sau đó có thể được sử dụng trong XAML như thế này:

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

3
Tốt nhất là khi triển khai ConvertBack tạo một bản sao của bộ sưu tập và đảo ngược nó, sau đó Tổng hợp lại? Vì vậy, ConvertBack sẽ làreturn this.Reverse<IValueConverter>().Aggregate(value, (current, converter) => converter.ConvertBack(current, targetType, parameter, culture));
Nick Udell

5
@DLeh Điều này không thực sự thanh lịch vì nó không hoạt động. Nó cung cấp cho tất cả các bộ chuyển đổi loại mục tiêu cuối cùng thay vì loại mục tiêu chính xác ...
Aleksandar Toplek

Làm cách nào tôi có thể sử dụng điều này với MultiValueConverter làm Bộ chuyển đổi đầu tiên?
LightMonk

1
@Town Một đồng nghiệp vừa tìm thấy câu hỏi này và nó khiến tôi phải tra cứu lại, vì nỗi nhớ. Chỉ có điều, tôi chỉ nhận thấy rằng bạn không nhận được tín dụng xứng đáng (Tôi đã chấp nhận câu trả lời của chính mình !), Vì vậy bây giờ tôi đã đánh dấu câu trả lời của bạn là được chấp nhận. Chỉ có khoảng 9 năm muộn ...: facepalm:
Mal Ross

@MalRoss Haha! Cảm ơn bạn! Thật tốt khi biết rằng nó vẫn hữu ích, tôi đã không chạm vào Silverlight bây giờ trong khoảng 8 năm trong số đó và đây vẫn là câu trả lời phổ biến nhất của tôi :)
Town

54

Đã tìm thấy chính xác những gì tôi đang tìm kiếm, nhờ sự hỗ trợ của Josh Smith: Bộ chuyển đổi giá trị đường ống (liên kết archive.org) .

Anh ấy định nghĩa một ValueConverterGrouplớp, mà việc sử dụng XAML chính xác như tôi đã hy vọng. Đây là một ví dụ:

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

Công cụ tuyệt vời. Cảm ơn, Josh. :)


2
Trong giải pháp này, mỗi bộ chuyển đổi chỉ phải xử lý một loại (nó phải được khai báo trong thuộc tính-ValueConversion-duy nhất). Giải pháp @Town cũng có thể đối phó với nhiều bộ biến tần.
Y. Shoham 19/12/12

9
xin vui lòng đăng thực hiện; nếu không, linkrot
Jake Berger

9

Thị trấn thực hiện dự án Silverlight của Gareth Evans là rất tốt, tuy nhiên nó không hỗ trợ các thông số chuyển đổi khác nhau.

Tôi đã sửa đổi nó để bạn có thể cung cấp các tham số, được phân cách bằng dấu phẩy (tất nhiên là trừ khi bạn thoát khỏi chúng).

Bộ chuyển đổi:

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

Lưu ý: ConvertBack không được triển khai ở đây, hãy xem Gist của tôi để biết phiên bản đầy đủ.

Thực hiện:

<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

Có, có nhiều cách để chuyển đổi chuỗi nhưng nó trông không đẹp và bạn không cần nó ở đây. Nếu bạn cần điều này, hãy tự hỏi bản thân rằng đó có thực sự là con đường để đi? Đơn giản luôn hoạt động tốt hơn ngay cả khi bạn phải viết trình chuyển đổi của riêng mình.

Trong trường hợp cụ thể của bạn, tất cả những gì bạn cần làm là định dạng một giá trị được chuyển đổi thành một chuỗi. StringFormattài sản trên a Bindinglà bạn của bạn ở đây.

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

5
Nếu bạn sử dụng nhiều ràng buộc, việc viết bộ chuyển đổi tùy chỉnh sang bộ chuyển đổi chuỗi sẽ dẫn đến hàng tấn bộ chuyển đổi câm cho tất cả các loại cấu hình. Trong trường hợp đó, câu trả lời được chấp nhận là một giải pháp tuyệt vời.
Jacek Gorgoń

0

Đây là một phần mở rộng nhỏ về câu trả lời của Town để hỗ trợ đa ràng buộc:

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
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.