简体   繁体   中英

How do I bind to a validation rule in XAML

I am following the example given here:

https://social.tec.net.microsoft.com/wiki/contents/articles/31422.wpf-passing-a-data-bound-value-to-a-validation-rule.aspx

I get the exception at the following line in my DataTemplateSelector:

return element.FindResource("MinParameterDataTemplateThin") as DataTemplate;

"Unexpected record in Baml stream. Trying to add to MaximumValueValidation which is not a collection or has a TypeConverter."

Code:

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

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

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

public class MaxValueWrapper : DependencyObject
{
    public static readonly DependencyProperty MaxValueProperty =
        DependencyProperty.Register("MaxValue", typeof(double),
            typeof(MaxValueWrapper), new FrameworkPropertyMetadata(double.MaxValue));

    public int MaxValue
    {
        get => (int)GetValue(MaxValueProperty);
        set => SetValue(MaxValueProperty, value);
    }
}

public class MaximumValueValidation : ValidationRule
{
    public MaxValueWrapper MaxValueWrapper { get; set; }

    /// <summary>
    /// validate whether the input value is in range
    /// </summary>
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        try
        {
            if (value != null && ((string)value).Length > 0)
            {
                double userInput = double.Parse((string)value);
                if (userInput > MaxValueWrapper.MaxValue)
                    return new ValidationResult(false,
                        "Please enter a value <= Max " + MaxValueWrapper.MaxValue);
            }
        }
        catch (Exception e)
        {
            return new ValidationResult(false, $"Invalid characters or {e.Message}");
        }

        return ValidationResult.ValidResult;
    }

}

XAML:

    <DataTemplate x:Key="MinParameterDataTemplateThin">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="120"/>
            </Grid.ColumnDefinitions>
            <TextBlock Text="{Binding DisplayName, StringFormat='{}{0}:'}" Grid.Column="0" Margin="10,5,5,10" VerticalAlignment="Top" TextWrapping="Wrap"
                       Visibility="{Binding Visibility}" ToolTipService.ShowDuration="20000">
                <TextBlock.ToolTip>
                    <ToolTip DataContext="{Binding Path=PlacementTarget.DataContext, RelativeSource={x:Static RelativeSource.Self}}">
                        <TextBlock Text="{Binding Description}"/>
                    </ToolTip>
                </TextBlock.ToolTip>                                
            </TextBlock>

            <StackPanel Grid.Column="1" Orientation="Horizontal">
                <TextBox Margin="5" Width="50" VerticalAlignment="Top"
                         Visibility="{Binding Visibility}" IsEnabled="{Binding IsEnabled}">
                    <i:Interaction.Behaviors>
                        <utilities:SelectTextOfTextBox/>
                    </i:Interaction.Behaviors>
                    <TextBox.Resources>
                        <validations:BindingProxy x:Key="proxy" Data="{Binding}"/>
                    </TextBox.Resources>
                    <TextBox.Text>
                        <Binding Path="{Binding DefaultValue, StringFormat=N2}" Mode="TwoWay"
                                 UpdateSourceTrigger="PropertyChanged"
                                 ValidatesOnExceptions="True"
                                 NotifyOnValidationError="True"
                                 ValidatesOnNotifyDataErrors="True">
                            <Binding.ValidationRules>
                                <validations:MaximumValueValidation ValidatesOnTargetUpdated="True">
                                    <validations:MaximumValueValidation.MaxValueWrapper>
                                        <validations:MaxValueWrapper MaxValue="{Binding Data.MaxValue, Source={StaticResource proxy}}"/>
                                    </validations:MaximumValueValidation.MaxValueWrapper>
                                </validations:MaximumValueValidation>
                            </Binding.ValidationRules>
                        </Binding>
                    </TextBox.Text>
                </TextBox>
                <TextBlock Text="{Binding UnitSymbol}" Margin="5" VerticalAlignment="Top" Visibility="{Binding Visibility}"/>
            </StackPanel>
        </Grid>
    </DataTemplate>

I have several working DataTemplates like this one, but they do not use validation rules with the TextBox. Perhaps I am not following the wiki example correctly, but I am not seeing the problem, and I don't understand the exception.

EDIT:

After staring at the exception message, it occurs to me that the "outer" DataTemplate might be relevant, but I cannot be sure. The DataTemplate above is for a WorkflowParameter object, which is part of a Collection nested in a parent WorkflowParameter object. The DataTemplate for this parent is:

    <DataTemplate x:Key="GroupedInversionParameterDataTemplate">
        <Grid Visibility="{Binding Visibility}">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="160"/>
                <ColumnDefinition Width="800"/>
            </Grid.ColumnDefinitions>
            <TextBlock Text="{Binding DisplayName, StringFormat='{}{0}:'}" Grid.Column="0" Margin="5" VerticalAlignment="Top" TextWrapping="Wrap"
                       Visibility="{Binding Visibility}" ToolTipService.ShowDuration="20000">
                <TextBlock.ToolTip>
                    <ToolTip DataContext="{Binding Path=PlacementTarget.DataContext, RelativeSource={x:Static RelativeSource.Self}}">
                        <TextBlock Text="{Binding Description}"/>
                    </ToolTip>
                </TextBlock.ToolTip>                                
            </TextBlock>
            <ItemsControl ItemsSource="{Binding GroupedWorkflowParameters}" Grid.Column="1"
                          ItemTemplateSelector="{StaticResource WorkflowParameterTemplateSelector}"
                          IsTabStop="False">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <WrapPanel Orientation="Horizontal"/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemContainerStyle>
                    <Style TargetType="ContentPresenter">
                        <Setter Property="Visibility" Value="{Binding Visibility}"/>
                    </Style>
                </ItemsControl.ItemContainerStyle>
            </ItemsControl>

        </Grid>

    </DataTemplate>

The mention of trying to add a collection, in the exception message, made me think that the ItemsControl in this outer template could be a problem. I would not expect it to be an issue, but maybe I am missing something.

I though the problem as with the validation XAML, so I commented it out and found there was still an exception. This snippet of XAML:

<Binding Path="{Binding DefaultValue, StringFormat=N2}"

had to change to

<Binding Path="DefaultValue" StringFormat="N2"

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