【问题标题】:Manage the targetType of a Binding in a MultiBinding在 MultiBinding 中管理 Binding 的 targetType
【发布时间】:2017-08-04 17:14:12
【问题描述】:

所以,我有一个带有转换器的多重绑定,它接受一些值并找到它们的最大值。问题是其中一个绑定使用了一个转换器,该转换器需要double 目标类型,而绑定具有object 目标类型。我想知道是否有任何方法可以以任何方式修改绑定的目标类型。

下面是我的 xaml 的近似值:

<TextBlock>
  <TextBlock.Width>
    <MultiBinding Converter="{StaticResource _maxValueConverter}">
      <Binding Source="{StaticResource _constantZeroValue}"/>
      <Binding Path="ActualWidth"
               ElementName="_previousTextBlock"
               Converter="{StaticResource _requiresDoubleTargetConverter}"/>
    </MultiBinding>
  </TextBlock.Width>
</TextBlock>

所以基本上如果有任何方法可以告诉第二个绑定它正在输出一个双精度值,那就太好了。

最小可验证完整示例:

MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        xmlns:local="clr-namespace:WpfApplication1"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        Title="MainWindow" Height="350" Width="525">
   <StackPanel>
      <StackPanel.Resources>
         <sys:Double x:Key="constantZero">0</sys:Double>
         <local:RequiresDoubleTargetConverter x:Key="requiresDoubleTargetConverter" />
         <local:MaxValueConverter x:Key="maxValueConverter" />
      </StackPanel.Resources>

      <Border x:Name="topBorder"
              BorderThickness="1"
              BorderBrush="Black"
              HorizontalAlignment="Left">
         <TextBlock x:Name="topTextBlock"
                    Background="Aqua"
                    Text="{Binding TopText}" />
      </Border>

      <Border BorderThickness="1"
              BorderBrush="Black"
              MinWidth="100"
              HorizontalAlignment="Left">
         <TextBlock Background="ForestGreen"
                 Text="{Binding BottomText}"
                 TextWrapping="Wrap"
                 MinWidth="100">
            <TextBlock.Width>

               <MultiBinding Converter="{StaticResource maxValueConverter}">
                  <MultiBinding.Bindings>
                     <Binding Path="ActualWidth" ElementName="topTextBlock" Converter="{StaticResource requiresDoubleTargetConverter}" />
                     <Binding Source="{StaticResource constantZero}" />
                  </MultiBinding.Bindings>
               </MultiBinding>

            </TextBlock.Width>
         </TextBlock>
      </Border>

   </StackPanel>
</Window>

MainWindow.xaml.cs

using System;
using System.Diagnostics;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace WpfApplication1
{
   /// <summary>
   /// Interaction logic for MainWindow.xaml
   /// </summary>
   public partial class MainWindow : Window
   {
      public string TopText
      {
         get { return "Hello World!"; }
      }

      public string BottomText
      {
         get { return "hi earth."; }
      }

      public MainWindow()
      {
         InitializeComponent();
      }
   }

   public class RequiresDoubleTargetConverter : IValueConverter
   {
      public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
      {
         // I am looking for a way to manually ensure that "targetType == typeof(double)" evaluates to true.
         if (targetType != typeof(double))
         {
            return null;
         }
         else
         {
            // Actual converter performs this calculation.
            return (double)value - 14;
         }
      }

      public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
      {
         // Irrelevant method for our purposes.
         throw new NotImplementedException();
      }
   }

   public class MaxValueConverter : IMultiValueConverter
   {
      public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
      {
         double max = double.NegativeInfinity;
         foreach (object value in values)
         {
            if (value is double)
            {
               max = Math.Max((double)value, max);
            }
            else
            {
               Debug.Fail("All values must be doubles");
            }
         }

         return max;
      }

      public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
      {
         // Irrelevant method for our purposes.
         throw new NotImplementedException();
      }
   }
}

这是使用 Visual Studio 2015 创建的,并经过验证以显示错误行为。我要确定的是是否可以从 xaml 手动设置RequiresDoubleTargetConvertertargetType

【问题讨论】:

  • 与其检查targetType,不如检查value 参数的类型并提供适当转换的值,例如如图所示:stackoverflow.com/q/27080733/1136211
  • 我试图避免对第二个转换器进行更改,因为它在我们的应用程序中的很多地方都使用过,在进行更改之前我需要做一些分析。跨度>
  • 关于使用传入类型的好技巧。唯一的问题是该值是否为空,因为您将看不到该类型是什么。

标签: wpf xaml binding converter


【解决方案1】:

就类型系统而言,绑定在object 上运行。如果你想要一个特定的类型,你需要自己确保。

但是,您可以使用传递给转换器的目标类型来确定所需的类型,并相应地修改转换器的返回值。

【讨论】:

  • 那么有没有办法手动设置转换器的目标类型,还是我坚持它是object
  • “您可以使用传递给转换器的目标类型来确定需要哪种类型,并相应地修改转换器的返回值” - 这可能是 OP 已经做的,他们的问题是目标传递给转换器的类型在这里是 object,因为 Binding 是 MultiBinding 的一部分。
  • 对了,有办法改变吗?
【解决方案2】:

那么有没有办法手动设置转换器的目标类型,还是我坚持它是对象?

您被 object 所困扰,因为 Convert 方法的签名始终相同,即它接受 object[] 的值,仅此而已。

您必须在您的Convert 方法中将values[1] 转换为double(因为该方法将始终且仅传递object 类型的值):

double d = (double)values[1];

【讨论】:

  • 恐怕这没有抓住问题的重点。是的,提供的值的类型是object,但它也有一个targetType 参数。目前targetType == typeof(object) 是真的,但我想要一种方法让targetType == typeof(double) 评估为真。
  • 所以你是说IMultiValueConverter的targetType参数不返回typeof(double)?请包括一个验证这一点的示例:stackoverflow.com/help/mcve
【解决方案3】:

我想出了解决这个问题的方法,但它只有在您可以访问您在 MultiBinding 本身上使用的转换器时才有效(或者您可以添加一个。)以及如果它需要一些额外的努力还使用 ConverterParameter、TargetNullValue 和/或 StringFormat。

诀窍是当您将子绑定添加到 MultiBinding 时,您会从该子绑定中删除 Converter、ConverterParameter、TargetNullValue 和 StringFormat 值,并将它们存储在 MultiBinding 转换器的 Convert 方法可访问的位置。 (我们使用包装器 MarkupExtension 来模拟 MultiBinding,因此我们可以在它们实际应用之前访问所有内容,因为它们一旦被应用,您就无法更改它们。)

然后在 MultiBinding 的 Convert 方法中,您现在从子绑定中获取原始的、尚未转换/格式化/合并的值,但您也有您需要的最终目标(在本例中为 double)它被交给了您所在的 MultiBinding 的 Convert 方法。

利用这些信息,您可以手动调用子转换器的 Convert 方法,传入尚未转换的值、targetType(传递给您)和 childConverterParameter。

您获取该调用的结果,如果为 null,则从子绑定返回 TargetNullValue。

如果不为null且targetType都是字符串且你有String Format,最后格式化结果。

这是伪代码(即在我的脑海中。Prolly 很多语法错误等。对于实际代码,你可以看到我在我的 DynamicResourceBinding 类中使用它,我在 StackOverflow here .)

// Convert function for the MultiBinding
private object Convert(object[] values, Type targetType, object parameter, Culture culture){

    var rawChildBindingResult = values[0]; // assuming it's in the first position

    var convertedChildBindingResult = childConverter(rawChildBindingResult, targetType, childConverterParameter, culture);

    if(convertedChildBindingResult == null)
        convertedChildBindingResult = childTargetNullValue;
    else if(targetType == typeof(string) && childStringFormat != null)
        convertedChildBindingResult = string.Format(childStringFormat, convertedChildBindingResult);

    // Now do whatever you would with the 'convertedChildBindingResult' as if things were normal
}

再次,查看链接以在上下文中查看它。

希望这会有所帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-13
    • 2014-03-30
    • 2012-04-25
    • 2019-02-11
    • 1970-01-01
    • 2019-10-22
    • 2010-11-08
    • 1970-01-01
    相关资源
    最近更新 更多