在MultiBinding中管理绑定的targetType [英] Manage the targetType of a Binding in a MultiBinding

查看:65
本文介绍了在MultiBinding中管理绑定的targetType的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,我与转换器进行了多重绑定,该转换器接受一些值并找到它们的最大值.问题在于绑定之一利用了期望double目标类型的转换器,而绑定具有object目标类型.我想知道是否有任何方法可以以任何方式修改绑定的目标类型.

So, I have a multi-binding with a converter that takes in some values and finds the max of them. The problem is that one of the bindings utilises a converter that expects a double target type, while the binding has an object target type. I was wondering if there was any way to modify the target type of a binding in any way.

以下是我的xaml的近似值:

Below is an approximation of my xaml:

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

因此,基本上,如果有任何方法可以告诉第二个绑定它正在输出为double值,那就太好了.

So basically if there is any way to tell the second binding that it is outputting to a double value, that'd be great.

最小可验证的完整示例:

Minimal Verifiable Complete Example:

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.

This was created using Visual Studio 2015, and is verified to show the erroneous behaviour. What I am trying to determine is if it is possible to manually set the targetType of the RequiresDoubleTargetConverter from the xaml.

推荐答案

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

I've come up with a way around this, but it only works if you have access to the converter you're using on the MultiBinding itself (or you can add one.) as well as a little extra effort if it also uses a ConverterParameter, TargetNullValue and/or a StringFormat.

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

The trick is when you add the child Binding to the MultiBinding, you remove the Converter, ConverterParameter, TargetNullValue and StringFormat values from that child binding and store them somewhere that's accessible by the Convert method for the MultiBinding's converter. (We use a wrapper MarkupExtension to simulate the MultiBinding so we have access to everything before they're actually applied as once they are, you can't change them.)

然后,在MultiBinding的Convert方法中,您现在从子绑定中获取原始的,尚未转换/格式化/合并的值,但您还拥有所需的最终目标(在此示例中为double):它已交给您所在的MultiBinding的Convert方法.

Then in the MultiBinding's Convert method, you're now getting the raw, not-yet-converted/formatted/coalesced value from the child binding, but you also have the ultimate target that you need (double in this example) as it was handed to the Convert method for the MultiBinding that you're in.

使用这些信息,然后您手动调用子转换器的Convert方法,传入尚未转换的值,targetType(传递给您)和childConverterParameter.

With that information, you then call the child converter's Convert method manually, passing in the not-yet-converted value, the targetType (passed in to you), and the childConverterParameter.

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

You take the result of that call, and if null, return the TargetNullValue from the child binding.

如果它不为null,并且两个targetType都是一个字符串,并且您具有字符串格式,则最后格式化结果.

If it's not null and both targetType is a string and you have a String Format, finally format the results.

这是伪代码(即,我的头顶.大量语法错误等.对于实际代码,您可以看到我在StackOverflow DynamicResourceBinding类中使用它) ="https://stackoverflow.com/a/49159501/168179">此处.)

Here's pseudo-code (i.e. off the top of my head. Prolly lots of syntax errors, etc. For the actual code, you can see me using it in my DynamicResourceBinding class that I have up on 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
}

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

Again, take a look at the link to see it in context.

希望这会有所帮助!

这篇关于在MultiBinding中管理绑定的targetType的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆