WPF:ValueConverter (IValueConverter) 不起作用

WPF: ValueConverter (IValueConverter) does not work

我有一个 Window class,其中我有几个 TextBlock 元素应该接收 Background 颜色 Binding 属性。第一个 "Converter binding" 工作正常并且完成了预期的一切。今天我尝试用另一个 Converter 实现另一个 "Converter binding",但它不起作用:

(我省略了 ConvertBack 方法,因为它们在这里不是必需的):

namespace InsightTool.Gui.Helper {
    [ValueConversion(typeof(double), typeof(Brush))]
    public class AverageExecutionTimeToColorConverter : IValueConverter {
        public object Convert (object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            double val;
            double.TryParse(value.ToString(), out val);

            if (val >= 10000) {
                return Brushes.Red;
            } else if (val >= 5000) {
                return Brushes.Orange;
            } else {
                return Brushes.Green;
            }
        }
    }

    [ValueConversion(typeof(int), typeof(Brush))]
    public class ThreadsAvailableCountToColorConverter : IValueConverter {
        public object Convert (object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            int val;
            int.TryParse(value.ToString(), out val);

            if (val < 100) {
                return Brushes.Red;
            } else if (val < 200) {
                return Brushes.Orange;
            } else if (val < 500) {
                return Brushes.Yellow;
            } else {
                return Brushes.Green;
            }
        }
    }
}

Window class 中,我使用了以下两个转换:

<Window ...
    x:Name="Main"
    xmlns:Base="clr-namespace:InsightTool.Gui.Helper">
    <Window.Resources>
        <Base:ThreadsAvailableCountToColorConverter x:Key="ThreadsAvailableCntConverter"/>
        <Base:AverageExecutionTimeToColorConverter x:Key="AvgExecutionTimeConverter"/>     
    </Window.Resources>

    <!-- This one works fine-->
    <TextBlock Width="10" Height="10" VerticalAlignment="Center" Background="{Binding ExecutionTimeAverage, Converter={StaticResource AvgExecutionTimeConverter}, ElementName=UCExecutionTimes}"/>

    <!-- This one does not work-->
    <TextBlock Width="10" Height="10" VerticalAlignment="Center" Background="{Binding ThreadsAvailableCount, Converter={StaticResource ThreadsAvailableCntConverter}, ElementName=Main}"/>
</Window>

DependencyProperties 的声明:

public partial class UserControlExecutionTimes : UserControl {
    public static readonly DependencyProperty ExecutionTimeAverageProperty =
             DependencyProperty.Register("ExecutionTimeAverage", typeof(double), typeof(MainWindow), new FrameworkPropertyMetadata(double));

    public double ExecutionTimeAverage {
        get { return (double)GetValue(ExecutionTimeAverageProperty); }
        set { SetValue(ExecutionTimeAverageProperty, value); }
    }
}


public partial class MainWindow : Window {
    public static readonly DependencyProperty ThreadsAvailableCountProperty = DependencyProperty.Register("ThreadsAvailableCount", typeof(int),
         typeof(MainWindow), new FrameworkPropertyMetadata(int));

    public int ThreadsAvailableCount {
        get { return (int)GetValue(ThreadsAvailableCountProperty); }
        set { SetValue(ThreadsAvailableCountProperty, value); }
    }
}

两个 DependencyProperties 都设置正确并且它们的值显示在 GUI 中。我在这里想念什么?

编辑:

我还测试了以下内容:

<Window>
    <!-- This one works fine-->
    <TextBlock Width="10" Height="10" VerticalAlignment="Center" Background="{Binding ThreadsAvailableCount, Converter={StaticResource AvgExecutionTimeConverter}, ElementName=Main}"/>

    <!-- This one does not work-->
    <TextBlock Width="10" Height="10" VerticalAlignment="Center" Background="{Binding ThreadsAvailableCount, Converter={StaticResource ThreadsAvailableCntConverter}, ElementName=Main}"/>
</Window>

似乎Binding消耗"new"转换器的return值有问题,但我不知道为什么。

EDIT2

我用 Snoop 检查绑定,结果如下:

工作转换器绑定的 background 属性 如下所示:

但是不工作的转换器绑定的 background 属性 看起来是这样的:

ThreadsAvailableCount 设置正确的另一个证明(绑定到 Textblock):

显示ThreadsAvailableCountToColorConverter的return值越来越像错误了。这是因为在 Debug 模式下,它会在 ThreadsAvailableCountToColorConverterConvert 方法中的断点处停止。它甚至在 Convert 方法中成功到达 return

我认为可能存在多个问题,请查看 'output window' 以了解绑定表达式错误。 1) 确保文本框呈现在不同的区域,而不是 重叠。 2)使用相对路径获取控件,在绑定表达式

中使用属性

你的转换器看起来不错。

以下是我的xaml

<Window x:Class="WhosebugBinding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:WhosebugBinding="clr-namespace:WhosebugBinding"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <WhosebugBinding:ThreadsAvailableCountToColorConverter x:Key="ThreadsAvailableCntConverter"/>
        <WhosebugBinding:AverageExecutionTimeToColorConverter x:Key="AvgExecutionTimeConverter"/>
    </Window.Resources>
    <Grid>
        <!--<DatePicker 
        x:Name="newtally" 
        Text="{Binding CustomerLastTally,Mode=TwoWay}"  
        Margin="0 0 0 0" 
        />-->
        <!-- This one works fine-->
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" Grid.Column="0" Width="30" Height="30" Text="Break"/>
        <TextBlock Grid.Row="1" Grid.Column="0"  Width="30" Height="30" VerticalAlignment="Center"  Text="Break" Background="{Binding ExecutionTimeAverage, Converter={StaticResource AvgExecutionTimeConverter}, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>

        <!-- This one does not work-->
        <TextBlock Grid.Row="2" Grid.Column="0"  Width="30" Height="30" VerticalAlignment="Center" Text="Break" Background ="{Binding ThreadsAvailableCount, Converter={StaticResource ThreadsAvailableCntConverter}, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
    </Grid>

</Window>

以下是我背后的代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WhosebugBinding
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        // Dependency Property
        public static readonly DependencyProperty ExecutionTimeAverageProperty =
             DependencyProperty.Register("ExecutionTimeAverage", typeof(DateTime),
             typeof(MainWindow), new FrameworkPropertyMetadata(DateTime.Now));

        // .NET Property wrapper
        public DateTime ExecutionTimeAverage
        {
            get { return (DateTime)GetValue(ExecutionTimeAverageProperty); }
            set { SetValue(ExecutionTimeAverageProperty, value); }
        }

        // Dependency Property
        public static readonly DependencyProperty ThreadsAvailableCountProperty =
             DependencyProperty.Register("ThreadsAvailableCount", typeof(int),
             typeof(MainWindow), new FrameworkPropertyMetadata(40));

        // .NET Property wrapper
        public int ThreadsAvailableCount
        {
            get { return (int)GetValue(ThreadsAvailableCountProperty); }
            set { SetValue(ThreadsAvailableCountProperty, value); }
        }
    }
}

以下是我的转换器

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
using System.Windows.Media;

namespace WhosebugBinding
{

    [ValueConversion(typeof(double), typeof(Brush))]
    public class AverageExecutionTimeToColorConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            double val;
            double.TryParse(value.ToString(), out val);

            if (val >= 10000)
            {
                return Brushes.Red;
            }
            else if (val >= 5000)
            {
                return Brushes.Orange;
            }
            else
            {
                return Brushes.Green;
            }
        }

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

    [ValueConversion(typeof(int), typeof(Brush))]
    public class ThreadsAvailableCountToColorConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            int val;
            int.TryParse(value.ToString(), out val);

            if (val < 100)
            {
                return Brushes.Red;
            }
            else if (val < 200)
            {
                return Brushes.Orange;
            }
            else if (val < 500)
            {
                return Brushes.Yellow;
            }
            else
            {
                return Brushes.Green;
            }
        }

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

啊!终于解决了这个问题。我有同样的问题。使用 TextBlock,使用 IValueConverter 转换为 Brush.

绑定有效,没有错误或输出。该值进入 IValueConverter 代码,我可以直接调试到 return 语句,然后......什么都没有!

你做的一切都是对的,但是你自动导入了错误的Brushes。我一直用 WPF 做这件事。

替换 using 语句:

using System.Drawing

与:

using System.Windows.Media

WPF 使用 System.Windows.Media.Brushes,但 非常 很容易导入几乎相同的 System.Drawing.Brushes 而没有注意到。一切看起来都很好,直到 WPF 掌握它并且不能实际使用它。但是它失败了 'gracefully' 回到默认颜色。