【问题标题】:Binding ConverterParameter绑定转换器参数
【发布时间】:2020-08-07 10:35:28
【问题描述】:

有没有办法在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>

我只需要将顶级父级的Tag 和控件本身的Tag 发送到我的转换器类。

【问题讨论】:

    标签: wpf xaml styles


    【解决方案1】:

    不,很遗憾,这是不可能的,因为 ConverterParameter 不是 DependencyProperty,因此您将无法使用绑定

    但也许您可以作弊并使用MultiBindingIMultiValueConverter 来传递2 个Tag 属性。

    【讨论】:

      【解决方案2】:

      ConverterParameter 属性不能绑定,因为它不是依赖属性。

      由于Binding 不是从DependencyObject 派生的,它的任何属性都不能是依赖属性。因此,一个 Binding 永远不能成为另一个 Binding 的目标对象。

      但是,还有一个替代解决方案。您可以使用 MultiBindingmulti-value converter 而不是普通的绑定:

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

      多值转换器获取源值数组作为输入:

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

      【讨论】:

        【解决方案3】:

        还有另一种使用MarkupExtension 的方法,以便将Binding 用于ConverterParameter。使用此解决方案,您仍然可以使用默认的IValueConverter 而不是IMultiValueConverter,因为ConverterParameter 就像您在第一个示例中所期望的那样传递到IValueConverter

        这是我的可重复使用的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) };
                }
            }
        }
        

        在您的代码库中使用此MarkupExtension,您可以通过以下方式简单地绑定ConverterParameter

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

        这看起来几乎像您最初的提案。

        【讨论】:

        • 这很有用。但是,MultiValueConverterAdapter 不见了。我找到了here
        • 它不适用于 Xamarin 表单,因为 multiBinding.ProvideValue(serviceProvider) 不存在。有什么选择吗?
        猜你喜欢
        • 2011-05-22
        • 2013-10-09
        • 2016-04-21
        • 1970-01-01
        相关资源
        最近更新 更多