ValidatesOnDataErrors in UserControl



  • Hallo,

    In einem Usercontrol habe ich eine Textbox

    <TextBox Text="{Binding Text, ElementName=MyUserControl, ValidatesOnDataErrors=True}" />
    

    Der Text ist an eine DependencyProperty im Usercontrol gebunden.

    public String Text
    {
        get { return (String)this.GetValue(TextProperty); }
        set { this.SetValue(TextProperty, value); }
    }
    public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
        "Text", typeof(String), typeof(MyUserControl), new PropertyMetadata(String.Empty));
    

    Nun verwende ich das UserControl:

    <controls:MyUserControl Text="{Binding Name}"/>
    

    Steht jetzt ein Fehler an wird der rote Rahmen nicht angezeigt.

    Setze ich ValidatesOnDataErrors wie folgt wird der Rahmen angezeigt.
    Allerdings um das ganze Control.

    <controls:MyUserControl Value="{Binding Name, ValidatesOnDataErrors=True}"/>
    

    Wie bekomme ich es hin dass in meinem UserControl ValidatesOnDataErrors nur auf die Textbox anzuwenden? Und so dass ich es im Usercontrol setzen kann und nicht jedesmal bei der Verwendung.



  • Kann mir hier keiner weiterhelfen?



  • Hallo ich bin ein Troll und troll hier rum. So jetzt gibts sicher eine Antwort.



  • Guten Morgen,

    evtl. hilft dir dieser Link ein bischen weiter?



  • Hallo PuppetMaster2k

    Den Beitrag habe ich auch schon gefunden.

    Doch leider kann ich mit der Lösung. Bzw. Dem Lösungssatz:

    Ich habe nun ein DP vom Typ Data in MyCustomControl, an dieses binden sich
    die "GUI" und auch der Style von MyCustomControl. Dadurch klappt es.

    überhaupt nichts anfangen.

    Oder kannst du mir das erklären.



  • Dein ganzer Ansatz ist unrichtig, du machst das Binding auf der UI - Ebene und dann gibst den Style aufs ganze Control. Normal bindest du nur dein Control ins UI ein und that's it. Der Rest der Logik kommt ins Control.

    Referenz:
    http://msdn.microsoft.com/en-us/library/system.windows.data.binding.validatesondataerrors.aspx



  • Danke für deine Antwort. Aber auch nach mehrmaligem lesen verstehe ich nur Bahnhof.

    du machst das Binding auf der UI - Ebene.

    Und das mache ich wie?

    und dann gibst den Style aufs ganze Control.

    Was für ein Style. Ich habe doch nirgends einen Style.

    Sorry dass ich es nicht verstehe.



  • Das hier...

    <controls:MyUserControl Value="{Binding Name, ValidatesOnDataErrors=True}"/>
    

    ...darfst du nicht auf der UI (User Interface) Ebene machen, sonst wird der Style, also der rote Rahmen, auf's ganze Control angewendet.

    Auf der UI - Ebene sollte lediglich folgendes stehen:

    <controls:MyUserControl />
    

    Mein Tipp: Verbastel das msdn - Example vom "ValidatesOnDataErrors Property" in ein UserControl, dann siehst du wie's funktioniert 😉



  • Darf ich nochmals nachfragen:
    Das hier

    <controls:MyUserControl />
    

    wollte ich ja auch so haben. Aber ich muss doch dem Control mitgeben welchen Inhalt er darstellen soll.

    Das hier ist doch das was ich mindestens machen muss.
    <controls:MyUserControl Text="{Binding Name}"/>

    In dem Beispiel sehe ich auch nicht wie ich den Name übergebe.



  • Also nochmals genau erklärt In meiner View habe ich ein Stackpanel mit mehreren Instanzen meines Controls. Nennt sich also LabelTextBox.

    Der DatenContext meiner View ist ein ViewModel mit mehreren Propertys die ich an die Usercontrols binden will

    <StackPanel>
     <LabelTextBox Header="Name" Text="{Binding Name}"/>
     <LabelTextBox Header="Nachname" Text="{Binding Lastname}"/>
     <LabelTextBox Header="Alter" Text="{Binding Age}"/>
    </StackPanel>
    

    Klar kann ich das Beispiel umsetzen. Hier erkenne ich aber nicht wie ich die Werte an das UserControl übergeben soll.



  • Schick mal mehr code, aus dein snippes komme ich nicht draus...



  • Was soll ich denn noch zeigen.

    Wie meine View aus sieht sollte doch klar sein

    Den ganzen Code drum herum ist doch unwichtig für das Beispiel.

    Aber wenns sein muss:

    <UserControl       x:Class="MyApplication"
                       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                       d:DesignHeight="900"
                       d:DesignWidth="1000"
                       mc:Ignorable="d">
    
    <StackPanel>
     <LabelTextBox Header="Name" Text="{Binding Name}"/>
     <LabelTextBox Header="Nachname" Text="{Binding Lastname}"/>
     <LabelTextBox Header="Alter" Text="{Binding Age}"/>
    </StackPanel>
    </UserControl>
    

    Mein Viewmodel das an den Datencontext gebunden ist hat halt Propertys die PropertyChanged aufrufen und mit dem Attribut Required ausgestattet sind. Aber gut ich poste auch diesen Code.

    class public class MyViewModel : ViewModelBase
    {
           [Required]
           public string Name
           {
             get { return GetValue<string>(Name); }  // Funktionen aus Basisklasse die Property Changed aufrufen.
             set { SetValue(Name, value); }
           }
    
          // die restlichen Property sind gleich
    }
    

    Das Control auch noch?

    Aber ich denke hier liegt ja das Problem wo ich nicht weiß wie implementieren.

    Was fehlt noch?



  • Hey, nich pampig werden!!! Es zwingt dich ja niemand und keiner kann ahnen was du da rumfrickels. Du hast hier alles was du baruchst um dein problem zu lösen, damit bin ich raus. Nice weekend ➡



  • Werd doch gar nicht pampig. Wenns so rüberkam: Entschuldigung.
    Mir war nur nicht klar was ich noch zeigen soll. Sorry nochmals.

    Du hast hier alles was du baruchst um dein problem zu lösen

    Mag sein aber ich verstehs halt nicht 😞



  • Ok, verstehe 🙂

    Nun dann, wenn du das msdn - Example auf das notwendigste runterbrichst, also auf "ValidatesOnDataErrors" und "DependencyProperty", könnte das ganz so aussehen.

    UserControl1.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" 
                 mc:Ignorable="d" 
                 d:DesignHeight="300" d:DesignWidth="300"
                 x:Name="usc">   
        <Grid>
            <TextBox Width="150" Height="25">
                <TextBox.Text>
                    <Binding Path="Age" ElementName="usc" ValidatesOnDataErrors="True" UpdateSourceTrigger="PropertyChanged"/>
                </TextBox.Text>
            </TextBox>
        </Grid>     
    </UserControl>
    

    UserControl1.xaml.cs

    using System.Windows;
    using System.Windows.Controls;
    
    namespace WpfApplication1
    {
        public partial class UserControl1 : UserControl
        {
            public UserControl1()
            {
                InitializeComponent();
            }
    
            public static readonly DependencyProperty AgeProperty = DependencyProperty.Register("Age",
               typeof(int), typeof(UserControl1));
    
            public int Age
            {
                get { return (int)this.GetValue(AgeProperty); }
                set { this.SetValue(AgeProperty, value); }
            }
        }
    }
    

    MainWindow.xaml

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525"
            xmlns:src="clr-namespace:WpfApplication1">
        <Grid>
            <src:UserControl1 Age="23"/>
            <src:UserControl1 Age="123" Margin="0,32,0,-32"/>
        </Grid>
    </Window>
    

    Du siehst das "ValidatesOnDataErrors" im UserControl implementiert ist. Die Logik spielt sich also komplett im UserControl ab und beim Anziehen im MainWindow wird nur noch das DependencyProperty "Age" übergeben, sonst nichts. Alle anderen Properties die du im Mainwindow für das UserControl angibst, wird nicht auf das einzelne Element angewendet, sondern auf's komplette UserControl.



  • Hallo Spud

    Vielen Dank für deine Hilfe. Und für die ausführliche Anleitung.

    Habe mir dein Beispiel genauesten angeschaut. Doch kann ich keinen Unterschied feststellen zu dem was ich implementiert und in meinem ersten Thread dargestellt habe. Ausser ein paar Details.

    Usercontrol:
    Meins:

    <TextBox Text="{Binding Text, ElementName=MyUserControl, ValidatesOnDataErrors=True}" />
    

    Deins:

    <TextBox Width="150" Height="25">
       <TextBox.Text>
          <Binding Path="Age" ElementName="usc" ValidatesOnDataErrors="True" UpdateSourceTrigger="PropertyChanged"/>
       </TextBox.Text>
    </TextBox>
    

    UserControl Code Behind:
    Meins:

    public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
        "Text", typeof(String), typeof(MyUserControl), new PropertyMetadata(String.Empty));
    
    public String Text
    {
        get { return (String)this.GetValue(TextProperty); }
        set { this.SetValue(TextProperty, value); }
    }
    

    Deins:

    public static readonly DependencyProperty AgeProperty = DependencyProperty.Register("Age",
               typeof(int), typeof(UserControl1));
    
    public int Age
    {
        get { return (int)this.GetValue(AgeProperty); }
        set { this.SetValue(AgeProperty, value); }
    }
    

    MainWindow:
    Meins:

    <controls:MyUserControl Text="{Binding Name}"/>
    

    Deins:

    <src:UserControl1 Age="23"/>
    

    Wo liegt den hier der Unterschied der das ganze funktionieren lassen soll.
    Also mal abgesehen von den Unterschiedlichen Namen, Datentypen usw.



  • Also, zum einem fehlt bei dir der UpdateSourceTrigger="PropertyChanged" im Text - Property und zum anderen Frage ich mich, nach was für'ner Regel du ValidatesOnDataErrors auslösen lässt(?), wenn du ein ein string als DependencyProperty - Typ verwendest.



  • Also, zum einem fehlt bei dir der UpdateSourceTrigger="PropertyChanged" im Text - Property

    Klar fehlt das, weil ich möchte das erst ausgelöst wird wenn ich den Focus wechsle. Aber an dem kann es ja nicht liegen.

    und zum anderen Frage ich mich, nach was für'ner Regel du ValidatesOnDataErrors auslösen lässt(?), wenn du ein ein string als DependencyProperty - Typ verwendest.

    Über das Attribute Required aus System.ComponentModel.DataAnnotations;

    Hatte ich glaub ich schon erwähnt. Und das funktioniert ja, wenn ich das ganze ohne usercontrol mache.



  • Und das funktioniert ja, wenn ich das ganze ohne usercontrol mache.

    Aha, ich gehe mal davon aus das du da kein DependencyProperty eingesetzt hast. Beim DependencyProperty benötigt's du ein Callback aus dieser Abhängigkeit, um Eingaben/Daten wieder zurückzuliefern und auszuwerten.

    Also wieder am msdn - Example in Verbindung mit dem IDataErrorInfo - Interface:

    Code-Behind UserInterface

    using System.ComponentModel;
    using System.Windows;
    using System.Windows.Controls;
    
    namespace WpfApplication1
    {
        public partial class UserControl1 : UserControl, IDataErrorInfo
        {
            public UserControl1()
            {
                InitializeComponent();
            }
    
            public static readonly DependencyProperty AgeProperty = DependencyProperty.Register("Age",                                                                    
                typeof(int), typeof(UserControl1),new PropertyMetadata(new PropertyChangedCallback(OnChangedValue))); // callback delegate erzeugen
    
            public int Age
            {
                get { return (int)this.GetValue(AgeProperty); }
                set { this.SetValue(AgeProperty, value); }
            }
    
            // statische methode für -PropertyChangedCallback-
            private static void OnChangedValue(DependencyObject d, DependencyPropertyChangedEventArgs e) 
            {
                age = (int)e.NewValue;
            }
    
            private static int age = 0;
    
            public string Error
            {
                get
                {
                    return "";
                }
            }
    
            public string this[string name]
            {
                get
                {
                    string result = null;
    
                    if (name == "Age")
                    {
                        if (age < 0 || age > 150)
                        {
                            result = "Age must not be less than 0 or greater than 150.";
                        }
                    }
                    return result;
                }
            }
        }
    }
    


  • Hallo Spud

    Aha, ich gehe mal davon aus das du da kein DependencyProperty eingesetzt hast

    ?? Das ist doch ein DependencyProperty oder nicht?

    public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
        "Text", typeof(String), typeof(MyUserControl), new PropertyMetadata(String.Empty));
    
    public String Text
    {
        get { return (String)this.GetValue(TextProperty); }
        set { this.SetValue(TextProperty, value); }
    }
    
    public string this[string name]
            {
                get
                {
                    string result = null;
    
                    if (name == "Age")
                    {
                        if (age < 0 || age > 150)
                        {
                            result = "Age must not be less than 0 or greater than 150.";
                        }
                    }
                    return result;
                }
            }
        }
    

    Und das kann ich ja nicht innerhalb meines Controls mache. Die Regeln werden ja ausserhalb definiert.

    Einmal wird zwingend eine Eingabe benötigt, einmal ein Bereich usw. Das darf nicht im Control gemacht werden.


Anmelden zum Antworten