Convertisseur de liaison


165

Y a-t-il un moyen de le faire de manière 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>

J'ai simplement besoin d'envoyer le Tagparent de niveau supérieur et le Tagcontrôle lui-même à ma classe de convertisseur.

Réponses:


303

La ConverterParameterpropriété ne peut pas être liée car ce n'est pas une propriété de dépendance.

Puisque Bindingn'est dérivé d' DependencyObjectaucune de ses propriétés, il peut s'agir de propriétés de dépendance. Par conséquent, une liaison ne peut jamais être l'objet cible d'une autre liaison.

Il existe cependant une solution alternative. Vous pouvez utiliser a MultiBindingavec un convertisseur à valeurs multiples au lieu d'une liaison normale:

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

Le convertisseur à valeurs multiples obtient un tableau de valeurs source en entrée:

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

Non, malheureusement, cela ne sera pas possible car ce ConverterParametern'est pas le DependencyPropertycas, vous ne pourrez donc pas utiliser de liaisons

Mais peut-être pourriez-vous tricher et utiliser un MultiBindingavec IMultiValueConverterpour passer les 2 Tagpropriétés.


13

Il existe également une autre façon d'utiliser MarkupExtensionpour utiliser Bindingun fichier ConverterParameter. Avec cette solution, vous pouvez toujours utiliser la valeur par défaut IValueConverterau lieu du IMultiValueConvertercar le ConverterParameterest passé dans le IValueConvertercomme vous vous attendiez dans votre premier exemple.

Voici mon réutilisable 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) };
        }
    }
}

Avec ceci MarkupExtensiondans votre base de code, vous pouvez simplement lier de la ConverterParametermanière suivante:

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

Ce qui ressemble presque à votre proposition initiale.


4
C'est utile. Cependant, il MultiValueConverterAdaptermanque. Je l'ai trouvé ici .
blearyeye
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.