简体   繁体   中英

Why isn't my binding for a TextBox validation rule parameter working?

I have a user control with a TextBox that needs to be validated. The validation will vary according to the value of a dependency property in the UC, so I need to pass that as a parameter. To pass a parameter I'm using Passing a data-bound value to a validation rule as a guide. However, the binding I'm using doesn't work and I don't know why. I've beat my head against it, googled everything I can think of, no joy.

Here's the code. Hopefully I've provided enough ...

In the user control I have this 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>

The problem lies in this binding, where NumberBoxUsage1 is a dependency property in validation environment and NumberBoxUsage is a dependency property in the UC.

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

When it runs, NumberBoxUsage1 remains the default and isn't assigned the value of NumberBoxUsage . I can change the binding to a literal assignment and that works. I've added a dummy converter, as shown, as well as PresentationTraceSources but the converter is never called and there is no trace in the Output window. Any help appreciated.

I might add that everything else in this TextBox works fine. Here's the relevant C# stuff.

Wrapper

   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
}

You are missing the BindingProxy that captures the DataContext :

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));
}

XAML:

<TextBox.Resources>
    <local:NumberBoxValueConverter x:Key="NumberBoxConverter"/>
    <local:BindingProxy x:Key="proxy" Data="{Binding RelativeSource={RelativeSource AncestorType=UserControl}}"/>
</TextBox.Resources>
...
<local:Wrapper NumberBoxUsage1="{Binding Source={StaticResource proxy}, Path=Data.NumberBoxUsage, 
    Converter={StaticResource DebugDummyConverter}}" />

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM