Want to pass parameters to WPF user control validation logic

Asked 2 years ago, Updated 2 years ago, 144 views

Creating user controls in WPF (.NET 4.5/C#).
A text box extension that also implements input validation.
We would like to pass parameters to this validation logic in the following ways:

<local:UserControl1Value="{Binding Foo}"TargetType="{x:Typelocal:AnyType}"/>

The TargetType property allows you to specify a class to customize the validation logic.
In implementing this mechanism, we used the explanatory articles on this site.
Here's the code:

UserControl 1.xaml

<UserControl x: Class="WpfApplication1.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns: x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns: mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WpfApplication1"
             mc —Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <TextBox>
            <TextBox.Text>
                <Binding Path="Value"
                         UpdateSourceTrigger="LostFocus"
                         RelativeSource="{RelativeSourceFindAncestor,AncestorType={x:TypeUserControl}}"
                         NotifyOnValidationError="True"
                         >
                    <Binding.ValidationRules>
                        <local:HogeRule>
                            <local: HogeRule.TargetType>
                                <local:DependencyTypeValue="{BindingTargetType,RelativeSource={RelativeSourceFindAncestor,AncestorType={x:TypeUserControl}}}"/gt;
                            </local: HogeRule.TargetType>
                        </local: HogeRule>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>
    </Grid>
</UserControl>

Code Behind

public partial class UserControl1:UserControl
{
    public UserControl1()
    {
        InitializeComponent();
    }

    // Value Dependency Properties
    public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
        "Value",
        type of (object),
        type of (UserControl1),
        new FrameworkPropertyMetadata(default(object), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault);

    // Value CLR Properties
    public object value
    {
        get {return this.GetValue(ValueProperty);}
        set {this.SetValue(ValueProperty, value);}
    }

    // TargetType Dependency Properties
    public static readonly DependencyProperty TargetTypeProperty=DependencyProperty.Register(
        "TargetType",
        type of (Type),
        type of (UserControl1),
        new FrameworkPropertyMetadata(default(object), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault);

    /// TargetType CLR Properties
    public Type TargetType
    {
        get {return(Type)this.GetValue(TargetTypeProperty);}
        set {this.SetValue (TargetTypeProperty, value);}
    }
}

Basic Validation Rules

public class HogeRule:ValidationRule
{
    public HogeRule()
    {
        this.TargetType = new DependencyType();
    }

    public DependencyTypeTargetType{get;set;}

    public override ValidationResultValidate(object value, System.Globalization.CultureInfo)
    {
        // Customize the process using TargetType.Value
    }
}

DependencyObject

used to pass Type type by data bind
public class DependencyType:DependencyObject
{
    public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
        "Value",
        type of (Type),
        type of (DependencyType),
        new FrameworkPropertyMetadata(default(object), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault);

    public Type Value
    {
        get {return(Type)this.GetValue(ValueProperty);}
        set {this.SetValue(ValueProperty, value);}
    }
}

However, even if you move this code, TargetType.Value is null when HogeRule.Validate is executed.
UserControl1.xaml

<local:DependencyTypeValue="{BindingTargetType,RelativeSource={RelativeSourceFindAnceptor,AnceptorType={x:TypeUserControl}}}}"/gt;

The row in is

<local:DependencyTypeValue="{x:Type local:AnyType}"/>

If you write fixedly, it works fine, so I think the binding here is not working well.
But I don't know what's wrong.
All you want to do is allow user control users to specify validation parameters, so you can take a completely different approach.

c# .net wpf xaml

2022-09-30 19:43

2 Answers

This is probably not possible with scope-dependent Binding.ElementName.The reference article uses {StaticResource}, so I think the VM has been able to resolve the issue by ignoring the visual tree.

So if you want to force a solution, use a special class like CollectionViewSource for example

<UserControl.Resources> 
    <CollectionViewSource
        x —Key = "cvs" >
        <CollectionViewSource.Source>
            <CompositeCollection>
                <local:DependencyType
                    Value="{Binding TargetType}"/>
            </CompositeCollection>
        </CollectionViewSource.Source>
    </CollectionViewSource>
</UserControl.Resources>

and resources defined.

<local:HogeRule.TargetType>
    <local:DependencyType
        Value="{Binding Source={StaticResource cvs}, Path=CurrentItem.Value}"/>
</local: HogeRule.TargetType>

You need to do something terrible, such as .

Also, if you don't mind changing the visual tree,

<UserControl>
    <UserControl.Resources>
        <Gridx: Key="grid" Visibility="Collapsed"/>
    </UserControl.Resources>
    <Grid>
        <StaticResourceExtensionResourceKey="grid"/>
        …
    </Grid>
<UserControl>

You can also deploy hidden controls and use the same instance as {Binding Source={StaticResource grid}, Path=DataContext.…} as shown in .


2022-09-30 19:43

I have not verified it, but I do not think UserControl and local:DependencyType are parent-child relationships.
Why don't you name UserControl with x:Name and refer to ElementName on the DependencyType side?

<UserControl x: Class="WpfApplication1.UserControl1"
         x: Name = "UserControl"
         (Omitted)
         d:DesignHeight="300" d:DesignWidth="300">

<local:DependencyTypeValue="{BindingTargetType,ElementName=UserControl}"/>


2022-09-30 19:43

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.