locked
ValidationRule failure is not shown for controls inside a Frame RRS feed

  • Question

  • The UserControl with a TextBox below is written to show a validation failure (using a default ErrorTemplate) at startup due to an initially empty text box.  The failure is indeed correctly shown when the control is hosted inside a Window.  But when this control is hosted inside a Frame, the failure is not shown at startup.  You need to type something in the TextBox and clear it, only then the validation failures start to show.  Is this a bug?  Is there a workaround?


    <UserControl x:Class="Validation2.DaUserControl" 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:local="clr-namespace:Validation2">  
        <UserControl.Resources>  
            <local:SomeTextValidationRule x:Key="SomeTextValidationRule"/>  
        </UserControl.Resources>  
        <TextBox Width="100">  
            <TextBox.Text>  
                <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type UserControl}}" Path="SomeText" Mode="OneWayToSource" UpdateSourceTrigger="PropertyChanged">  
                    <Binding.ValidationRules>  
                        <StaticResource ResourceKey="SomeTextValidationRule" />  
                    </Binding.ValidationRules>  
                </Binding>  
            </TextBox.Text>  
        </TextBox>  
    </UserControl> 

    namespace Validation2  
    {  
        public partial class DaUserControl : UserControl  
        {  
            public DaUserControl()  
            {  
                InitializeComponent();  
            }  
     
            public string SomeText { get; set; }  
        }  
     
        public class SomeTextValidationRule : ValidationRule  
        {  
            public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)  
            {  
                if (value.ToString().Length == 0)  
                {  
                    return new ValidationResult(false, "SomeText should not be empty");  
                }  
     
                return new ValidationResult(true, null);  
            }  
        }  
     
    Wednesday, October 29, 2008 2:31 AM

Answers

  • This works for me:

    <UserControl x:Class="Validation2.DaUserControl"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:Validation2">
      <UserControl.Resources>
        <local:SomeTextValidationRule x:Key="SomeTextValidationRule"/>
      </UserControl.Resources>
      <TextBox Width="100">
        <TextBox.Style>
          <Style TargetType="{x:Type TextBox}">
            <Style.Triggers>
              <Trigger Property="IsVisible" Value="True">
                <Setter Property="Text">
                  <Setter.Value>
                    <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type UserControl}}" Path="SomeText" Mode="OneWayToSource" UpdateSourceTrigger="PropertyChanged">
                      <Binding.ValidationRules>
                        <StaticResource ResourceKey="SomeTextValidationRule"/>
                      </Binding.ValidationRules>
                    </Binding>
                  </Setter.Value>
                </Setter>
              </Trigger>
            </Style.Triggers>
          </Style>
        </TextBox.Style>
      </TextBox>
    </UserControl>

    That said, I set the binding on Text property only when the TextBox is visible this usually happens when the visual tree is correctly set it up.

    The root cause is when is binding expression is updating the ValidationError, and needs to show the validation error adorer, because at this time, the visual tree is not ready, which means that the Adorner layer has not been set up, that's why the validation error cannot be displayed.

    Hope this helps



    Monday, November 3, 2008 7:15 AM

All replies

  • The code you pasted above works pretty well for me, which version of .NET Framework you are using, I made the test under .NET Framework 3.5 SP1.

    Thanks
    Friday, October 31, 2008 7:25 AM
  • I'm using .NET Framework 3.5 SP1 as well.  Here is a driver program that uses the above DaUserControl and illustrates the problem:

     
    <Window x:Class="Validation2.Window1" 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:local="clr-namespace:Validation2" 
        Title="Window1" Height="300" Width="300">  
        <StackPanel> 
            <local:DaUserControl/> 
            <Button Click="OnCreateFrame">Create New DaUserControl for Frame.Content</Button> 
            <Frame Name="mFrame"/>  
        </StackPanel> 
    </Window> 
     
    namespace Validation2  
    {  
        public partial class Window1 : Window  
        {  
            public Window1()  
            {  
                InitializeComponent();  
            }  
     
            private void OnCreateFrame(object sender, RoutedEventArgs e)  
            {  
                mFrame.Content = new DaUserControl();  
            }  
        }  
    Friday, October 31, 2008 5:26 PM
  • This works for me:

    <UserControl x:Class="Validation2.DaUserControl"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:Validation2">
      <UserControl.Resources>
        <local:SomeTextValidationRule x:Key="SomeTextValidationRule"/>
      </UserControl.Resources>
      <TextBox Width="100">
        <TextBox.Style>
          <Style TargetType="{x:Type TextBox}">
            <Style.Triggers>
              <Trigger Property="IsVisible" Value="True">
                <Setter Property="Text">
                  <Setter.Value>
                    <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type UserControl}}" Path="SomeText" Mode="OneWayToSource" UpdateSourceTrigger="PropertyChanged">
                      <Binding.ValidationRules>
                        <StaticResource ResourceKey="SomeTextValidationRule"/>
                      </Binding.ValidationRules>
                    </Binding>
                  </Setter.Value>
                </Setter>
              </Trigger>
            </Style.Triggers>
          </Style>
        </TextBox.Style>
      </TextBox>
    </UserControl>

    That said, I set the binding on Text property only when the TextBox is visible this usually happens when the visual tree is correctly set it up.

    The root cause is when is binding expression is updating the ValidationError, and needs to show the validation error adorer, because at this time, the visual tree is not ready, which means that the Adorner layer has not been set up, that's why the validation error cannot be displayed.

    Hope this helps



    Monday, November 3, 2008 7:15 AM
  • Thanks Marco!  That works for me.  Now, is this behavior considered a feature or a bug that will be fixed?
    Monday, November 3, 2008 6:18 PM
  • -> Thanks Marco!  That works for me.  Now, is this behavior considered a feature or a bug that will be fixed?

    I think it's an unfortunate side effect that Validation mechanism uses the adorner to display the validation error, but data binding engine could activate/evaluate the binding expression before the visual tree is constructed.

    If you think this is a bug, you could file a bug on the connect site:

    https://connect.microsoft.com/feedback/default.aspx?SiteID=212&wa=wsignin1.0


    Thanks
    Tuesday, November 4, 2008 3:49 AM