Binding ConverterParameter


165

Có cách nào tôi có thể làm điều này trong Style:

<Style TargetType="FrameworkElement">
    <Setter Property="Visibility">
        <Setter.Value>
            <Binding Path="Tag"
                RelativeSource="{RelativeSource AncestorType=UserControl}"
                Converter="{StaticResource AccessLevelToVisibilityConverter}"
                ConverterParameter="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Tag}" />                        
        </Setter.Value>
    </Setter>
</Style>

Tôi chỉ cần gửi Tagphụ huynh cấp cao nhất và Tagchính điều khiển đến lớp trình chuyển đổi của tôi.

Câu trả lời:


303

Tài ConverterParametersản không thể bị ràng buộc bởi vì nó không phải là một tài sản phụ thuộc.

Bindingkhông bắt nguồn từ DependencyObjectkhông thuộc tính nào của nó có thể là thuộc tính phụ thuộc. Kết quả là, Binding không bao giờ có thể là đối tượng mục tiêu của Binding khác.

Tuy nhiên, có một giải pháp thay thế. Bạn có thể sử dụng một MultiBindingvới một chuyển đổi đa giá trị thay vì một Binding bình thường:

<Style TargetType="FrameworkElement">
    <Setter Property="Visibility">
        <Setter.Value>
            <MultiBinding Converter="{StaticResource AccessLevelToVisibilityConverter}">
                <Binding Path="Tag" RelativeSource="{RelativeSource Mode=FindAncestor,
                                                     AncestorType=UserControl}"/>
                <Binding Path="Tag" RelativeSource="{RelativeSource Mode=Self}"/>
            </MultiBinding>
        </Setter.Value>
    </Setter>
</Style>

Bộ chuyển đổi đa giá trị lấy một mảng các giá trị nguồn làm đầu vào:

public class AccessLevelToVisibilityConverter : IMultiValueConverter
{
    public object Convert(
        object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        return values.All(v => (v is bool && (bool)v))
            ? Visibility.Visible
            : Visibility.Hidden;
    }

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

36

Không, thật không may, điều này sẽ không thể thực hiện được vì ConverterParameterkhông phải DependencyPropertyvì vậy bạn sẽ không thể sử dụng các ràng buộc

Nhưng có lẽ bạn có thể gian lận và sử dụng a MultiBindingvới IMultiValueConverterđể vượt qua trong 2 Tagthuộc tính.


13

Ngoài ra còn có một cách khác để sử dụng MarkupExtensionđể sử dụng Bindingcho a ConverterParameter. Với giải pháp này, bạn vẫn có thể sử dụng mặc định IValueConverterthay IMultiValueConvertervì vì ConverterParameterđược truyền vào IValueConvertergiống như bạn mong đợi trong mẫu đầu tiên của mình.

Đây là tái sử dụng của tôi MarkupExtension:

/// <summary>
///     <example>
///         <TextBox>
///             <TextBox.Text>
///                 <wpfAdditions:ConverterBindableParameter Binding="{Binding FirstName}"
///                     Converter="{StaticResource TestValueConverter}"
///                     ConverterParameterBinding="{Binding ConcatSign}" />
///             </TextBox.Text>
///         </TextBox>
///     </example>
/// </summary>
[ContentProperty(nameof(Binding))]
public class ConverterBindableParameter : MarkupExtension
{
    #region Public Properties

    public Binding Binding { get; set; }
    public BindingMode Mode { get; set; }
    public IValueConverter Converter { get; set; }
    public Binding ConverterParameter { get; set; }

    #endregion

    public ConverterBindableParameter()
    { }

    public ConverterBindableParameter(string path)
    {
        Binding = new Binding(path);
    }

    public ConverterBindableParameter(Binding binding)
    {
        Binding = binding;
    }

    #region Overridden Methods

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        var multiBinding = new MultiBinding();
        Binding.Mode = Mode;
        multiBinding.Bindings.Add(Binding);
        if (ConverterParameter != null)
        {
            ConverterParameter.Mode = BindingMode.OneWay;
            multiBinding.Bindings.Add(ConverterParameter);
        }
        var adapter = new MultiValueConverterAdapter
        {
            Converter = Converter
        };
        multiBinding.Converter = adapter;
        return multiBinding.ProvideValue(serviceProvider);
    }

    #endregion

    [ContentProperty(nameof(Converter))]
    private class MultiValueConverterAdapter : IMultiValueConverter
    {
        public IValueConverter Converter { get; set; }

        private object lastParameter;

        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if (Converter == null) return values[0]; // Required for VS design-time
            if (values.Length > 1) lastParameter = values[1];
            return Converter.Convert(values[0], targetType, lastParameter, culture);
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            if (Converter == null) return new object[] { value }; // Required for VS design-time

            return new object[] { Converter.ConvertBack(value, targetTypes[0], lastParameter, culture) };
        }
    }
}

Với điều này MarkupExtensiontrong cơ sở mã của bạn, bạn có thể chỉ cần liên kết ConverterParametertheo cách sau:

<Style TargetType="FrameworkElement">
<Setter Property="Visibility">
    <Setter.Value>
     <wpfAdditions:ConverterBindableParameter Binding="{Binding Tag, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}"
                 Converter="{StaticResource AccessLevelToVisibilityConverter}"
                 ConverterParameterBinding="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Tag}" />          
    </Setter.Value>
</Setter>

Mà trông gần giống như đề xuất ban đầu của bạn.


4
Điều này rất hữu ích. Tuy nhiên, MultiValueConverterAdapterlà mất tích. Tôi tìm thấy nó ở đây .
blearyeye
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.