绑定一个已绑定的 属性 但具有规范化值

Binding an already bound property but with a normalised value

我的ProgressBarXAML:

<Window ...>
     <ProgressBar Value="{Binding Path=Progress}"/>
</Window>

代码隐藏:

internal int Progress { get; set; }

此进度变量是 1 的倍数,因此值为 1、2、3,依此类推...

现在我决定对 TaskBarItemInfoProgressValue 使用相同的 Progress 属性。但是,我发现它只接受 0.0 到 1.0 的范围(即 normalised 值)。有没有一种方法可以绑定相同的 Progress 属性,同时指定某种转换,例如除以数字以使其标准化?

xaml代码:

<Window.Resources>
     <local:DataConverter  x:Key="dataConverter " />
</Window.Resources>


 <ProgressBar Value={Binding Path=Progress, Converter={StaticResource dataConverter }}/>

转换器代码

public class DataConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
       // read the input from value and cast it
       // return your object;
    }

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

有多种选择。您可以公开一个单独的(可能是计算的)double 属性,每次 Progress 属性 更改时都会更新,例如通过在其 setter 中为计算出的 属性.

引发一个 PropertyChanged (INotifyPropertyChanged) 事件

另一种选择是创建自定义值或 multi-value 转换器。如果您的 int 进度值有硬编码或预定义的范围,您可以像这样创建一个值转换器。

public class AbsoluteToRelativeProgressConverter : IValueConverter
{
   public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
   {
      if (!(value is int progress) ||
          !(parameter is string maximumText) ||
          !int.TryParse(maximumText, out var maximum))
         return Binding.DoNothing;

      if (maximum < progress)
         throw new ArgumentException("Progress must not exceed maximum.");

      return progress / (double)maximum;
   }

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

此转换器获取作为 value 传入的绑定进度值。检查此值是否真的是 int。作为参数,您可以传递最大值。它作为 string 传递以简化 XAML 中的语法(分配 int 是冗长的)。转换器 returns 在 [0.0, 1.0] 范围内的相对进度为 double。如前所述,如果最大值是硬编码的,您可以删除参数用法并将 maximum 替换为值。

接下来,在 Window.Resources 或范围内的任何其他资源字典中创建转换器实例。

<Window.Resources>
   <local:AbsoluteToRelativeProgressConverter x:Key="AbsoluteToRelativeProgressConverter"/>
</Window.Resources>

然后使用转换器将TaskBarItemInfo中的Progress绑定到ProgressValueConverterParameter 用于传递最大值,这里以 100 为例。请注意,您需要将 ProgressState 设置为例如NormalErrorPaused,否则不显示进度条。

<Window.TaskbarItemInfo>
   <TaskbarItemInfo ProgressState="Normal"
                    ProgressValue="{Binding Progress, Converter={StaticResource AbsoluteToRelativeProgressConverter}, ConverterParameter=100}"/>
</Window.TaskbarItemInfo>
<Window.Resources>
   <local:AbsoluteToRelativeProgressMultiConverter x:Key="AbsoluteToRelativeProgressMultiConverter"/>
</Window.Resources>

如果你也想绑定最大值,你需要像这样创建一个IMultiValueConverter

public class AbsoluteToRelativeProgressMultiConverter : IMultiValueConverter
{
   public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
   {
      if (values is null ||
          values.Length != 2 ||
          !(values[0] is int progress) ||
          !(values[1] is int maximum))
         return Binding.DoNothing;

      if (maximum < progress)
         throw new ArgumentException("Progress must not exceed maximum.");

      return progress / (double)maximum;
   }

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

它的工作原理相同,但允许绑定多个值。在这里,进度是转换器的第一个值,最大值是第二个。您可以轻松地扩展此转换器,也可以绑定一个最小值。

在 XAML 中,您也创建了一个实例,但这次您使用 MultiBinding

<Window.Resources>
   <local:AbsoluteToRelativeProgressMultiConverter x:Key="AbsoluteToRelativeProgressMultiConverter"/>
</Window.Resources>

<Window.TaskbarItemInfo>
   <TaskbarItemInfo ProgressState="Normal">
      <TaskbarItemInfo.ProgressValue>
         <MultiBinding Converter="{StaticResource AbsoluteToRelativeProgressMultiConverter}">
            <Binding Path="Progress"/>
            <Binding Path="Maximum"/>
         </MultiBinding>
      </TaskbarItemInfo.ProgressValue>
   </TaskbarItemInfo>
</Window.TaskbarItemInfo>

注意,如果你想让 ProgressState 依赖于 Progress 属性,比如设置 Normal 如果进度是 >= 0<= maximum,你猜怎么着,你可以使用创建一个转换器......或者当然是一个单独的 属性。