Sam
Sam

Reputation: 586

ErrorTemplate showing for the user control and not the text box within it! How to fix?

There are similar questions to this one on here however I have tried the mentioned solutions to no avail!

Let me just run you through the setup - I have a model which implements IDataErrorInfo, a viewmodel which exposes the model to the view, within the view I have a usercontrol which is simply a labelled textbox, the model properties are binded to the usercontrol's inner textbox via a dependency property... and everything is binding correctly, all validation is fired and the correct errors returned! However, the usercontrol appears to be intercepting the error and thus the errortemplate of the usercontrol is displayed and not the textbox.

So, I know I can stop the usercontrol's error template from being displayed by setting the property to x:Null, however how do I trigger the textbox's error template to be displayed?! I have tried implementing IDataErrorInfo within the usercontrol (as advised by some) and explicitly defining the validation error template within the user control but I just can't get the darn thing to display. At this point I am thinking that the usercontrol is simply intercepting the error, holding onto it and not passing it onto the textbox, hence the errortemplate not being shown as it isn't aware of the error.

I have been pulling my hair out for the past day and really don't want to resort to not using the usercontrol as I know this can be achieved but I really don't know how to fix it! So if there are any wizards out there that can help I would be very grateful!

UserControl XAML:

<UserControl x:Class="PIRS_Client.Control.LabelTextBox"
         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" 
         mc:Ignorable="d" Height="40.541" Width="321.027">
<Grid Height="41" VerticalAlignment="Top" HorizontalAlignment="Left" Width="321">        
    <StackPanel Orientation="Horizontal" Margin="0,8,50,9">
    <Label Content="Label" Height="28" Name="BaseLabel" VerticalAlignment="Top" HorizontalContentAlignment="Right" Width="116" FontSize="11" />
        <TextBox Height="22" Width="100" Margin="0,0,0,0" x:Name="BaseTextBox" VerticalContentAlignment="Center" VerticalAlignment="Top" FontSize="11"/>
    </StackPanel>
</Grid>

UserControl Code:

public partial class LabelTextBox : UserControl
{

    public static readonly DependencyProperty TextBoxTextProperty = DependencyProperty.Register("TextBoxText", typeof(string), typeof(LabelTextBox), new FrameworkPropertyMetadata() { BindsTwoWayByDefault = true });

    public LabelTextBox()
    {
        InitializeComponent();

        Binding textBoxText = new Binding("TextBoxText") { Source = this, Mode = BindingMode.TwoWay };
        BaseTextBox.SetBinding(TextBox.TextProperty, textBoxText);
    }        

    [Browsable(true)]
    public string LabelText
    {
        get { return BaseLabel.Content.ToString(); }
        set
        {
            BaseLabel.Content = value;
        }
    }

    [Browsable(true)]
    public string TextBoxText
    {
        get { return (string)GetValue(TextBoxTextProperty); }
        set { SetValue(TextBoxTextProperty, value); }
    }

    [Browsable(true)]
    public double TextBoxWidth
    {
        get { return BaseTextBox.Width; }
        set
        {
            BaseTextBox.Width = value;
        }
    }
}

View - UserControl delcaration:

        <control:LabelTextBox HorizontalAlignment="Left" LabelText="Email" TextBoxText="{Binding UpdateSourceTrigger=LostFocus, Path=NewFosterCarerInfo.partner_email, ValidatesOnDataErrors=true, NotifyOnValidationError=true}" TextBoxWidth="120" Margin="190,182,-61,0" VerticalAlignment="Top" Height="41" Width="321"/>

Upvotes: 0

Views: 1774

Answers (1)

Sam
Sam

Reputation: 586

For anyone with my problem, here is the working code

UserControl xaml:

<UserControl x:Class="PIRS_Client.Control.LabelTextBox"
         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" 
         mc:Ignorable="d" Height="40.541" Width="321.027"             
         x:Name="Parent" Validation.ErrorTemplate="{x:Null}">

<Grid Height="41" VerticalAlignment="Top" HorizontalAlignment="Left" Width="321" DataContext="{Binding ElementName=Parent, ValidatesOnDataErrors=True}">
    <StackPanel Orientation="Horizontal" Margin="0,8,50,9">
        <Label Content="Label" Height="28" Name="BaseLabel" VerticalAlignment="Top" HorizontalContentAlignment="Right" Width="116" FontSize="11" />
        <TextBox Height="22" Text="{Binding Path=TextBoxText, ValidatesOnDataErrors=True}" Width="100" Margin="0,0,0,0" x:Name="BaseTextBox" VerticalContentAlignment="Center" VerticalAlignment="Top" FontSize="11"/>
    </StackPanel>
</Grid>

UserControl code behind:

public partial class LabelTextBox : UserControl, IDataErrorInfo
{       
    public LabelTextBox()
    {
        InitializeComponent();
    }

    public static readonly DependencyProperty TextBoxTextProperty =
        DependencyProperty.Register(
            "TextBoxText",
            typeof(string),
            typeof(LabelTextBox),
            new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)
    );

    #region IDataErrorInfo Members

    public string Error
    {
        get
        {
            if (Validation.GetHasError(this))
                return string.Join(Environment.NewLine, Validation.GetErrors(this).Select(e => e.ErrorContent));

            return null;
        }
    }

    public string this[string columnName]
    {
        get
        {
            // use a specific validation or ask for UserControl Validation Error 
            if (Validation.GetHasError(this))
            {
                var error = Validation.GetErrors(this).FirstOrDefault(e => ((BindingExpression)e.BindingInError).TargetProperty.Name == columnName);
                if (error != null)
                    return error.ErrorContent as string;
            }

            return null;
        }
    }

    #endregion

    [Browsable(true)]
    public string LabelText
    {
        get { return BaseLabel.Content.ToString(); }
        set { BaseLabel.Content = value; }
    }

    [Browsable(true)]
    public string TextBoxText
    {
        get { return (string)GetValue(TextBoxTextProperty); }
        set { 
            SetValue(TextBoxTextProperty, value);
        }
    }

    [Browsable(true)]
    public double TextBoxWidth
    {
        get { return BaseTextBox.Width; }
        set { BaseTextBox.Width = value; }
    }
}

Using the UserControl:

            <control:LabelTextBox HorizontalAlignment="Left" LabelText="Email" TextBoxText="{Binding Path=NewFosterCarerInfo.partner_email, ValidatesOnDataErrors=true}" TextBoxWidth="120" Margin="190,182,-61,0" VerticalAlignment="Top" Height="41" Width="321"/>

And in case you wanted a nice Validation.ErrorTemplate:

`<Style TargetType="{x:Type TextBox}">
    <Setter Property="VerticalAlignment" Value="Center" />
    <Setter Property="Margin" Value="0,2,40,2" />
    <Setter Property="Validation.ErrorTemplate">
        <Setter.Value>
            <ControlTemplate>
                <DockPanel LastChildFill="true">
                    <Border Background="Red" DockPanel.Dock="right" Margin="5,0,0,0" Width="20" Height="20" CornerRadius="10"
                                ToolTip="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
                        <TextBlock Text="!" VerticalAlignment="center" HorizontalAlignment="center" FontWeight="Bold" Foreground="white">
                        </TextBlock>
                    </Border>
                    <AdornedElementPlaceholder Name="customAdorner" VerticalAlignment="Center" >
                        <Border BorderBrush="red" BorderThickness="1" />
                    </AdornedElementPlaceholder>
                </DockPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>`

Upvotes: 4

Related Questions