【问题标题】:Converter With Multiple Parameters多参数转换器
【发布时间】:2012-07-04 05:56:48
【问题描述】:

如何在 Windows Phone 7 应用程序中使用具有多个参数的转换器?

【问题讨论】:

  • 尝试在 ConverterParameter 属性中传递逗号分隔的参数,并通过在 Converter 中拆分该值来获取参数值。
  • @Hitesh Patel:您不能使用逗号,因为这会与绑定 XAML 语法发生冲突。使用 XAML 允许的其他字符(可能是竖线“|”字符)?
  • 这就是你要找的stackoverflow.com/questions/55575968/… 吗?

标签: c# silverlight windows-phone-7 xaml ivalueconverter


【解决方案1】:

转换器始终实现IValueConverter。这意味着对ConvertConvertBack 的调用会传递一个附加参数。该参数是从 XAML 中提取的。

正如 Hitesh Patel 所建议的,没有什么可以阻止您将多个值放入参数中,只要您有一个分隔符稍后将它们分开,但您不能使用逗号分隔 XAML!

例如

XAML

<TextBlock Text="{Binding Path=ReleaseDate, Mode=OneWay,
                        Converter={StaticResource MyConverter}, 
                        ConverterParameter=Param1|Param2}" />

转换器

public object Convert(object value, Type targetType, object parameter,
    System.Globalization.CultureInfo culture)
{
    string parameterString = parameter as string;
    if (!string.IsNullOrEmpty(parameterString))
    {
        string[] parameters = parameterString.Split(new char[]{'|'});
        // Now do something with the parameters
    }
}

注意,我没有检查它是否是管道“|”字符在 XAML 中有效(应该),但如果不是,请选择另一个不冲突的字符。

.Net 的最新版本对于Split 的最简单版本不需要字符数组,因此您可以改用它:

string[] parameters = parameterString.Split('|');

附录:

多年前,eBay 在 url 中使用的一个技巧是用 QQ 分隔 URL 中的数据。文本数据中自然不会出现双 Q。如果您遇到避免编码问题的文本分隔符卡住了,请使用 QQ……这不适用于拆分(它需要单个字符,但很高兴知道):)

【讨论】:

  • Regex.Split('QQ')会在QQ分叉
  • @Simon_Weaver:是的,但是 Regex 比字符串方法慢得多(它们的存在是为了完成相同的工作),因此对于简单的任务,最好避免使用 Regex。谢谢
  • 值得注意的是这个参数不能是一个绑定。
  • 忽略“...Param2}}”之后的无关的'}'。应该是“...Param2}。
  • @BoiseBaked:谢谢。已修复。
【解决方案2】:

虽然上述答案可能是可行的,但它们似乎过于复杂。只需在 XAML 代码中使用 IMultiValueConverter 和适当的 MultiBinding。假设您的 ViewModel 具有属性 FirstValueSecondValueThirdValue,它们分别是 intdoublestring,一个有效的多转换器可能如下所示:

C#

public class MyMultiValueConverter : IMultiValueConverter {
  public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
    int firstValue = (int)values[0];
    double secondValue = (double)values[1];
    string thirdValue = (string)values[2];

    return "You said " + thirdValue + ", but it's rather " + firstValue * secondValue;
  }

  public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) {
    throw new NotImplementedException("Going back to what you had isn't supported.");
  }
}

XAML

<TextBlock.Text>
  <MultiBinding Converter="{StaticResource myNs:MyMultiValueConverter}">
    <Binding Path="FirstValue" />
    <Binding Path="SecondValue" />
    <Binding Path="ThirdValue" />
  </MultiBinding>
</TextBlock.Text>

由于它既不需要摸索MarkupExtension 所需的ProvideValue 方法,也不需要在转换器内部(!)指定DependencyObject,我相信这是最优雅的解决方案。

【讨论】:

  • 虽然技术上没有传递多个“参数”并且实际上传递了多个值。当然同样有效(至少对于我的需要)。非常感谢。
【解决方案3】:

您始终可以从 DependecyObject 类派生并添加任意数量的 DependencyProperty 对象。例如:

ExampleConverter.cs

public class ExampleConverter : DependencyObject, IValueConverter
{
    public string Example
    {
        get => GetValue(ExampleProperty).ToString();
        set => SetValue(ExampleProperty, value);
    }
    public static readonly DependencyProperty ExampleProperty =
        DependencyProperty.Register("Example", typeof(string), typeof(ExampleConverter), new PropertyMetadata(null));

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        //Do the convert
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

然后在 XAML 中:

ExampleView.xaml

<ResourceDictionary>
    <converters:ExampleConverter x:Key="ExampleConverter" Example="{Binding YourSecondParam}"/>
</ResourceDictionary>
...
<TextBlock Text="{Binding Path=ReleaseDate, Mode=OneWay,
                    Converter={StaticResource ExampleConverter}, 
                    ConverterParameter={Binding YourFirstParam}}" />

【讨论】:

  • 这看起来像一个优雅的解决方案,但我的转换器依赖属性从未设置
  • 如果没有更多详细信息,@RDV 很难为您提供帮助。我可以将您指向 DependencyObject 文档:docs.microsoft.com/pl-pl/dotnet/api/…
【解决方案4】:

这可以使用System.Windows.Markup.MarkupExtension (docs) 来完成。

这将允许您将值传递给可用作参数或返回值的转换器,例如:

public class CustomNullToVisibilityConverter : MarkupExtension, IValueConverter
{
    public object NullValue { get; set; }
    public object NotNullValue { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null) return NullValue;

        return NotNullValue;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

用法:

...
Visibility="{Binding Property, 
 Converter={cnv:CustomNullToVisibilityConverter NotNullValue=Visible, NullValue=Collapsed}}" 
/>
...

请务必在.xaml 中引用转换器的命名空间。

【讨论】:

  • 在UWP上,MarkupExtensionWindows.UI.Xaml.Markup中,ProvideValue没有任何参数。
【解决方案5】:

类似于 Kyle Olson 的回答,您可以像这样使用专业收藏:

XAML 文件:

xmlns:specialized="clr-namespace:System.Collections.Specialized;assembly=System"

<local:BoolToMessage x:Key="BoolToMessage"/>

<Label
    >
    <Label.Content>
        <Binding ElementName="mainWin" Path="HasSeedFile"
                FallbackValue="False" Converter="{StaticResource BoolToMessage}"
                Mode="OneWay">
            <Binding.ConverterParameter>
                <specialized:StringCollection>
                    <sys:String>param1</sys:String>
                    <sys:String>param2</sys:String>
                </specialized:StringCollection>
            </Binding.ConverterParameter>
        </Binding>
    </Label.Content>
</Label>

转换器:

using System.Collections.Specialized;

[ValueConversion(typeof(bool), typeof(string))]
public class BoolToMessage : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        string[] p = new string[((StringCollection) parameter).Count];
        ((StringCollection) parameter).CopyTo(p,0);

        return (bool) value ? p[0] : p[1];
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return null;
    }
}

有几种专业集合类型应该可以满足大多数需求。

【讨论】:

    【解决方案6】:

    Xamarin 的解决方案:

    public class BoolStateConverter : BindableObject, IValueConverter, IMarkupExtension
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var boolValue = (bool)value;
            return boolValue ? EnabledValue : DisabledValue;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return value;
        }
    
        public object ProvideValue(IServiceProvider serviceProvider)
        {
            return this;
        }
    
        public static BindableProperty EnabledValueProperty = BindableHelper.CreateProperty<string>(nameof(EnabledValue));
        public string EnabledValue
        {
            get => (string)GetValue(EnabledValueProperty);
            set => SetValue(EnabledValueProperty, value);
        }
    
        public static BindableProperty DisabledValueProperty = BindableHelper.CreateProperty<string>(nameof(DisabledValue));
        public string DisabledValue
        {
            get => (string)GetValue(DisabledValueProperty);
            set => SetValue(DisabledValueProperty, value);
        }
    }
    

    XAML 消耗:

    <ContentPage.Resources>
        <ResourceDictionary>
            <converters:BoolStateConverter
                x:Key="BackwardButtonConverter"
                EnabledValue="{x:Static res:Images.IcActiveButton}"
                DisabledValue="{x:Static res:Images.IcInactiveButton}" />
        </ResourceDictionary>
    </ContentPage.Resources>
    

    【讨论】:

      【解决方案7】:

      如果您的输入不适用于字符串,并且您有多个参数(不是绑定)。你可以只传递一个集合。定义需要的任何类型之一以避免数组的一些 UI 编辑器问题:

      public class BrushCollection : Collection<Brush>
      {
      }
      

      然后使用集合添加 XAML

                      <TextBox.Background >
                          <Binding Path="HasInitiativeChanged" Converter="{StaticResource changedToBrushConverter}">
                              <Binding.ConverterParameter>
                                  <local:BrushCollection>
                                      <SolidColorBrush Color="{DynamicResource ThemeTextBackground}"/>
                                      <SolidColorBrush Color="{DynamicResource SecondaryColorBMedium}"/>
                                  </local:BrushCollection>
                              </Binding.ConverterParameter>
                          </Binding>
      
                      </TextBox.Background>
      

      然后将结果转换为转换器中适当类型的数组:

          public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
          {
      
              BrushCollection brushes = (BrushCollection)parameter;
      

      【讨论】:

        猜你喜欢
        • 2020-08-07
        • 1970-01-01
        • 2019-08-01
        • 2018-10-05
        相关资源
        最近更新 更多