为什么我对TextBox验证规则参数的绑定不起作用?

时间:2019-06-06 16:09:30

标签: c# wpf xaml

我有一个带有TextBox的用户控件,需要进行验证。验证会根据UC中依赖项属性的值而有所不同,因此我需要将其作为参数传递。为了传递参数,我使用Passing a data-bound value to a validation rule作为指导。但是,我正在使用的绑定不起作用,我也不知道为什么。我为之奋斗,用谷歌搜索了我能想到的一切,没有喜悦。

这是代码。希望我已经提供了足够的...

在用户控件中,我有此XAML。

    <TextBox Name="ValueBox" 
            PreviewMouseLeftButtonUp="OnPreviewMouseLeftButtonUp" 
            Height="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=Height}"
            BorderThickness="0"
            TextAlignment="Center" 
            VerticalContentAlignment="Center">
        <TextBox.Style>
            <Style TargetType="TextBox">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=IsControlEnabled}"
                                 Value="False">
                        <Setter Property="Background" Value="{StaticResource DisabledColor}"/>
                    </DataTrigger>

                    <DataTrigger 
                                 Binding="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=InteractionMode}"
                                 Value="{x:Static local:TreatmentScheduleNumberBoxUserControl+InteractionModes.Select}">
                        <Setter Property="IsReadOnly" Value="True" />
                        <Setter Property="Cursor" Value="{x:Static Cursors.Hand}" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </TextBox.Style>
        <TextBox.Resources>
            <local:NumberBoxValueConverter x:Key="NumberBoxConverter"/>
        </TextBox.Resources>
        <TextBox.Text>
            <tools:ConverterBindableParameter
                Converter="{StaticResource NumberBoxConverter}"
                ConverterParameterBinding="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=TreatmentLampType}">
                <!--https://social.technet.microsoft.com/wiki/contents/articles/31422.wpf-passing-a-data-bound-value-to-a-validation-rule.aspx-->
                <tools:ConverterBindableParameter.Binding>
                    <Binding RelativeSource="{RelativeSource AncestorType=UserControl}" Path="Value" FallbackValue="3">
                        <Binding.ValidationRules>
                            <local:NumberBoxValidationRule>
                                <local:NumberBoxValidationRule.Wrapper>
                                    <local:Wrapper NumberBoxUsage1="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=NumberBoxUsage
                                        , Converter={StaticResource DebugDummyConverter, PresentationTraceSources.TraceLevel=High}}" />
                                </local:NumberBoxValidationRule.Wrapper>
                            </local:NumberBoxValidationRule>
                        </Binding.ValidationRules>
                    </Binding>
                </tools:ConverterBindableParameter.Binding>
            </tools:ConverterBindableParameter>
        </TextBox.Text>
    </TextBox>

问题在于此绑定,其中NumberBoxUsage1是验证环境中的依赖项属性,NumberBoxUsage是UC中的依赖项属性。

<local:Wrapper NumberBoxUsage1="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=NumberBoxUsage
, Converter={StaticResource DebugDummyConverter, PresentationTraceSources.TraceLevel=High}}" />

运行时,NumberBoxUsage1仍为默认值,未分配值为NumberBoxUsage。我可以将绑定更改为文字分配,并且可以使用。如图所示,我已经添加了一个虚拟转换器以及PresentationTraceSources,但是该转换器从未被调用过,并且在“输出”窗口中也没有踪迹。任何帮助表示赞赏。

我可能还要补充一点,TextBox中的其他所有内容都可以正常工作。这是相关的C#内容。

包装器

   public class Wrapper : DependencyObject
    {
        public NumberBoxUsages NumberBoxUsage1 {
            get => (NumberBoxUsages)GetValue(NumberBoxUsage1Property);
            set => SetValue(NumberBoxUsage1Property, value);
        }

        public static readonly DependencyProperty NumberBoxUsage1Property =
            DependencyProperty.Register(nameof(NumberBoxUsage1), typeof(NumberBoxUsages), typeof(Wrapper),
                new FrameworkPropertyMetadata(
                    NumberBoxUsages.UvPrim,
                    (sender, e) =>
                    {
                        var dObj = sender as Wrapper;
                        var x = dObj.NumberBoxUsage1;
                        // leave for debugging help
                    }
                ));
    }

NumberBoxValidationRule

public class NumberBoxValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        if (value == null)
        {
            return new ValidationResult(false, "Please enter a value");
        }

        if (Wrapper.NumberBoxUsage1 == NumberBoxUsages.UvbPriPct)
        {

        }

        return ValidationResult.ValidResult;
    }

    public Wrapper Wrapper { get; set; }
}

ConverterBindableParameter

public class ConverterBindableParameter : MarkupExtension
{
    #region Public Properties

    public Binding Binding { get; set; }

    public IValueConverter Converter { get; set; }

    public Binding ConverterParameterBinding { get; set; }

    #endregion

    #region Overridden Methods

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        var multiBinding = new MultiBinding();
        multiBinding.Bindings.Add(Binding);
        multiBinding.Bindings.Add(ConverterParameterBinding);
        var adapter = new MultiValueConverterAdapter
        {
            Converter = Converter
        };
        multiBinding.Converter = adapter;
        return multiBinding.ProvideValue(serviceProvider);
    }

    [ContentProperty("Converter")]
    public class MultiValueConverterAdapter : IMultiValueConverter
    {
        public IValueConverter Converter { get; set; }

        private object lastParameter;

        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if (Converter == null) return values[0]; // Required for VS design-time
            if (values.Length > 1) lastParameter = values[1];
            return Converter.Convert(values[0], targetType, lastParameter, culture);
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            if (Converter == null) return new object[] { value }; // Required for VS design-time

            return new object[] { Converter.ConvertBack(value, targetTypes[0], lastParameter, culture) };
        }
    }

    #endregion
}

1 个答案:

答案 0 :(得分:1)

您缺少捕获BindingProxy的{​​{1}}:

DataContext

XAML:

public class BindingProxy : System.Windows.Freezable
{
    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }

    public object Data
    {
        get { return (object)GetValue(DataProperty); }
        set { SetValue(DataProperty, value); }
    }

    public static readonly DependencyProperty DataProperty =
        DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new PropertyMetadata(null));
}