BindungskonverterParameter

165

Gibt es eine Möglichkeit, wie ich dies tun könnte 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>

Ich muss lediglich das Tagübergeordnete Element der obersten Ebene und das TagSteuerelement selbst an meine Konverterklasse senden .

Punkt net
quelle

Antworten:

303

Die ConverterParameterEigenschaft kann nicht gebunden werden, da es sich nicht um eine Abhängigkeitseigenschaft handelt.

Da Bindingnicht von DependencyObjectkeiner seiner Eigenschaften abgeleitet wird, können Abhängigkeitseigenschaften sein. Infolgedessen kann eine Bindung niemals das Zielobjekt einer anderen Bindung sein.

Es gibt jedoch eine alternative Lösung. Sie können einen KonverterMultiBinding mit mehreren Werten anstelle einer normalen Bindung verwenden:

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

Der Mehrwertkonverter erhält ein Array von Quellwerten als Eingabe:

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

Nein, dies ist leider nicht möglich, da dies nicht der Fall ConverterParameterist und DependencyPropertySie keine Bindungen verwenden können

Aber vielleicht könnten Sie betrügen und ein MultiBindingmit verwenden IMultiValueConverter, um die 2 TagEigenschaften zu übergeben.

sa_ddam213
quelle
13

Es gibt auch eine alternative Verwendung MarkupExtension, um Bindingfür a zu verwenden ConverterParameter. Mit dieser Lösung können Sie weiterhin die Standardeinstellung IValueConverteranstelle von verwenden, IMultiValueConverterda ConverterParameterdie IValueConvertergenau so übergeben wird, wie Sie es in Ihrem ersten Beispiel erwartet haben.

Hier ist meine wiederverwendbare 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) };
        }
    }
}

Mit diesem MarkupExtensionin Ihrer Codebasis können Sie einfach ConverterParameterden folgenden Weg binden :

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

Was fast wie Ihr ursprünglicher Vorschlag aussieht.

Pascalsz
quelle
4
Das ist nützlich. Allerdings MultiValueConverterAdapterfehlt. Ich habe es hier gefunden .
blearyeye