178 votes

Lier ConverterParameter

Y a-t-il un moyen de faire cela dans un 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 Tag du parent de niveau supérieur et le Tag de contrôle lui-même à ma classe de convertisseur.

340voto

Clemens Points 33376

Le site ConverterParameter ne peut pas être liée car il ne s'agit pas d'une propriété de dépendance.

Depuis Binding n'est pas dérivé de DependencyObject aucune de ses propriétés ne peut être une propriété de dépendance. En conséquence, un Binding ne peut jamais être l'objet cible d'un autre Binding.

Il existe cependant une autre solution. Vous pouvez utiliser un MultiBinding avec un convertisseur multi-valeurs au lieu d'une reliure 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 multi-valeurs reçoit en entrée un tableau de valeurs sources :

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

37voto

sa_ddam213 Points 18735

Non, malheureusement, cela ne sera pas possible car ConverterParameter n'est pas un DependencyProperty vous ne pourrez donc pas utiliser les liaisons

Mais vous pourriez peut-être tricher et utiliser un MultiBinding avec IMultiValueConverter pour passer dans le 2 Tag propriétés.

22voto

Pascalsz Points 168

Il existe également une autre façon d'utiliser MarkupExtension afin d'utiliser Binding pour un ConverterParameter . Avec cette solution, vous pouvez toujours utiliser l'option par défaut IValueConverter au lieu de la IMultiValueConverter parce que le ConverterParameter est passé dans le IValueConverter comme vous l'aviez prévu dans votre premier échantillon.

Voici ma 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 cette MarkupExtension dans votre base de code, vous pouvez simplement lier l'option ConverterParameter de la maniè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 votes

C'est utile. Cependant, MultiValueConverterAdapter a disparu. Je l'ai trouvé ici .

0 votes

Cela ne fonctionne pas sur Xamarin Forms car multiBinding.ProvideValue(serviceProvider) n'existe pas. Une alternative ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X