绑定到转换器参数

时间:2010-12-08 14:03:10

标签: .net xaml binding silverlight-4.0 converter

是否可以在Silverlight 4.0中绑定到ConverterParameter?

例如,我想做类似的事情,并将ConverterParameter绑定到ViewModel中的对象。

如果不可能,还有其他选择吗?

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

5 个答案:

答案 0 :(得分:54)

不幸的是,你无法绑定到ConverterParameter。我过去使用了两个选项:不是使用Converter,而是在ViewModel上创建一个属性(或者你绑定的任何属性),为你进行转换。如果您仍想使用转换器路径,请将整个绑定对象传递给转换器,然后您可以按照这种方式进行计算。

答案 1 :(得分:20)

另一个选择是通过创建一个自定义转换器来包装您的其他转换器并从属性传入转换器参数。只要此自定义转换器继承DependencyObject并使用DependencyProperty,就可以绑定它。例如:

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

    <c:ConverterParamHelper.Converter>

        <c:RealConverter/>

    </c:ConverterParamHelper.Converter>

</c:ConverterParamHelper>

答案 2 :(得分:17)

我知道这是一个老问题,但也许这对遇到它的人有用。我找到的解决方案如下:

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

并在您的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" />

答案 3 :(得分:0)

我找到了一条相关的SO帖子,我相信它可以回答以下问题:

WPF ValidationRule with dependency property

在我的特定示例中,我最终得到了实现以上示例的xaml:

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

答案 4 :(得分:0)

可以通过创建自己的Binding来支持到ConverterParameter的绑定。这是使用方法:

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

以及此绑定的实现代码:

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