【问题标题】:Binding to Converter Parameter绑定到转换器参数
【发布时间】:2011-05-22 06:14:30
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: .net xaml binding silverlight-4.0 converter


    【解决方案1】:

    可以通过创建自己的 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) };
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      我找到了一个相关的 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>
      

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

        • 这看起来应该可以工作,但我得到了旧的“找不到目标元素的管理 FrameworkElement 或 FrameworkContentElement”、“DataItem=null”业务。 UnitPropFromDataContext 是您的视图模型的属性吗?如果绑定无论如何都没有 DataItem,那就没关系了。
        • 这太可怕了,但它是唯一对我有用的东西:void View_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) { (FindResource("ConverterKey") as ConverterType).PropertyName = (DataContext as ViewModelType)。视图模型属性; }
        【解决方案4】:

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

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

        【讨论】:

        • 这种方法比使用 MultiBinding (switchonthecode.com/tutorials/wpf-tutorial-using-multibindings) 有优势吗?
        • 你能发布一个实现吗?
        • @Nathan 我想用这样的转换器实现ConvertBack 比使用MultiBinding 更容易。考虑一个TimeConverter,它将DateTime 转换为一个格式化的时间字符串。当使用MultiBinding 时,ConvertBack 只会得到格式化的字符串,这不足以解析整个DateTime。 Tim 的转换器也允许通过绑定到 ConvertBack 来传递日期。
        • @TimGreenfield 你能举个例子来说明如何使用它吗?
        • 嗨蒂姆,我很想试试这个,但我需要比上面显示的更多的上下文和信息。您能否包括所有必要的部分来设置它? ConverterParamHelper 的源代码是什么样的? RealConverter 不仅存在,而且存在于包含绑定到的控件的元素的上下文中,等等。在半现实示例中显示更多上下文将非常有帮助,因为我似乎无法获得这种方法工作。
        【解决方案5】:

        很遗憾,您不能绑定到 ConverterParameter。我过去使用过两个选项:不使用转换器,而是在您的 ViewModel(或您要绑定的任何东西)上创建一个属性来为您进行转换。如果您仍想走 Converter 路线,请将整个绑定对象传递给转换器,然后您可以通过这种方式进行计算。

        【讨论】:

        • 难道没有办法让转换器从DependencyObject 等继承吗?我正在创作一个自定义控件,我需要根据控件中的另一个属性来格式化绑定的对象。
        • “将整个绑定对象传递给转换器”是什么意思?
        • 将对象传递给转换器,该转换器具有您进行转换所需的所有属性。在转换器中,将传入的对象转换为特定类型。
        • 如果我将整个对象传递给转换器,我该如何实现ConvertBack?重新创建初始对象?只有当所有原始属性都作为value 传递给ConvertBack 时才有可能。
        • 与@Clément 相同的问题,我想看看如何绑定整个绑定对象(在我的情况下为数据上下文)。
        猜你喜欢
        • 2020-08-07
        • 2013-10-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多