47 votes

Liaison avec le paramètre du convertisseur

Est-il possible de se lier à un ConverterParameter dans Silverlight 4.0 ?

Par exemple, je voudrais faire quelque chose comme ceci et lier le ConverterParameter à un objet dans un ViewModel par exemple.

Si cela n'est pas possible, y a-t-il d'autres options ?

<RadioButton
  Content="{Binding Path=Mode}"
  IsChecked="{Binding
    Converter={StaticResource ParameterModeToBoolConverter},
    ConverterParameter={Binding Path=DataContext.SelectedMode,ElementName=root}}"
/>

57voto

Joe McBride Points 1944

Malheureusement non, vous ne pouvez pas vous lier à un ConverterParameter. Il y a deux options que j'ai utilisées dans le passé : au lieu d'utiliser un Converter, créez une propriété sur votre ViewModel (ou tout ce à quoi vous vous liez) qui fait la conversion pour vous. Si vous voulez toujours emprunter la voie du convertisseur, passez tout l'objet lié au convertisseur et vous pourrez alors effectuer vos calculs de cette façon.

3 votes

N'y a-t-il pas moyen de faire en sorte que le convertisseur hérite de DependencyObject etc. Je crée un contrôle personnalisé et j'ai besoin de formater l'objet lié en fonction d'une autre propriété du contrôle.

3 votes

Que voulez-vous dire par "passer l'objet lié entier au convertisseur" ?

0 votes

Passez l'objet au convertisseur qui possède toutes les propriétés nécessaires pour effectuer votre conversion. Dans le convertisseur, convertissez l'objet passé dans le type spécifique.

21voto

Tim Greenfield Points 391

Une autre option consiste à faire preuve de fantaisie en créant un convertisseur personnalisé qui englobe votre autre convertisseur et transmet un paramètre de convertisseur à partir d'une propriété. Tant que ce convertisseur personnalisé hérite de DependencyObject et utilise une DependencyProperty, il peut être lié. Par exemple :

<c:ConverterParamHelper ConverterParam="{Binding ...}">

    <c:ConverterParamHelper.Converter>

        <c:RealConverter/>

    </c:ConverterParamHelper.Converter>

</c:ConverterParamHelper>

1 votes

Cette approche présente-t-elle un avantage par rapport à l'utilisation d'un MultiBinding ( switchonthecode.com/tutorials/wpf-tutorial-utiliser-multibindings ) ?

1 votes

Pouvez-vous poster une implémentation ?

2 votes

@Nathan Je suppose que c'est plus facile à mettre en œuvre. ConvertBack avec un tel convertisseur qu'avec un MultiBinding. Considérons un TimeConverter qui convertit un DateTime en une chaîne de temps formatée. Lorsque vous utilisez un MultiBinding , ConvertBack n'obtiendra que la chaîne de caractères formatée, ce qui ne sera pas suffisant pour résoudre l'intégralité de l'appel. DateTime . Le convertisseur de Tim permet de passer une date via une liaison à ConvertBack également.

18voto

Adam Bilinski Points 794

Je sais que c'est une vieille question, mais peut-être que cela sera utile à quelqu'un qui l'a rencontrée. La solution que j'ai trouvée est la suivante :

public class WattHoursConverter : FrameworkElement, IValueConverter
    {

        #region Unit (DependencyProperty)

        /// <summary>
        /// A description of the property.
        /// </summary>
        public string Unit
        {
            get { return (string)GetValue(UnitProperty); }
            set { SetValue(UnitProperty, value); }
        }
        public static readonly DependencyProperty UnitProperty =
            DependencyProperty.Register("Unit", typeof(string), typeof(WattHoursConverter),
            new PropertyMetadata("", new PropertyChangedCallback(OnUnitChanged)));

        private static void OnUnitChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((WattHoursConverter)d).OnUnitChanged(e);
        }

        protected virtual void OnUnitChanged(DependencyPropertyChangedEventArgs e)
        {
        }

        #endregion

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
// you can use the dependency property here
...
}
}

et dans votre xaml :

<UserControl.Resources>
    <converters:WattHoursConverter x:Key="WattHoursConverter" Unit="{Binding UnitPropFromDataContext}"/>
 </UserControl.Resources>
....
  <TextBlock Grid.Column="1" TextWrapping="Wrap" Text="{Binding TotalCO2, Converter={StaticResource KgToTonnesConverter}}" FontSize="13.333" />

0 votes

Cela semble devoir fonctionner, mais je reçois le vieux message "Cannot find governing FrameworkElement or FrameworkContentElement for target element", "DataItem=null". Est-ce que UnitPropFromDataContext est une propriété de votre viewmodel ? Cela n'a pas d'importance si la liaison n'a pas de DataItem de toute façon.

0 votes

C'est horrible mais c'est la seule chose qui fonctionne pour moi : void View_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) {(FindResource("ConverterKey") as ConverterType).PropertyName = (DataContext as ViewModelType).ViewModelProperty ; }

1voto

Apfelkuacha Points 644

Cela est possible en créant un Binding propre qui supporte la liaison avec le ConverterParameter. Voici comment l'utiliser :

<RadioButton Content="{Binding Path=Mode}" 
    IsChecked="{BindingWithBindableConverterParameter Converter={StaticResource ParameterModeToBoolConverter},
    ConverterParameter={Binding Path=DataContext.SelectedMode,ElementName=root}}" />

Et le code avec l'implémentation pour cette liaison :

[ContentProperty(nameof(Binding))]
public class BindingWithBindableConverterParameter : MarkupExtension
{
    public Binding Binding { get; set; }
    public BindingMode Mode { get; set; }
    public IValueConverter Converter { get; set; }
    public Binding ConverterParameter { get; set; }

    public BindingWithBindableConverterParameter()
    { }

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

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

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

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

0voto

Mark Points 1

J'ai trouvé un post SO connexe qui, je pense, répond à cette question :

WPF ValidationRule avec propriété de dépendance

Dans mon exemple spécifique, je me retrouve avec un xaml qui ressemble à ceci après avoir mis en œuvre l'exemple ci-dessus :

<conv:BindingProxy x:Key="iconCacheHolder" Value="{Binding ElementName=This,Path=IconCache}" />
<conv:UriImageConverter  x:Key="ImageConverter">
    <conv:UriImageConverter.Proxy>
        <conv:IconCacheProxy Value="{Binding Value, Source={StaticResource iconCacheHolder}}" />
    </conv:UriImageConverter.Proxy>
</conv:UriImageConverter>

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