none
UserControl und Validierung RRS feed

  • Frage

  • Hallo,

    ich habe ein UserControl mit TextBoxen. Nun möchte ich eine Validurung über die "ValidationRule" von außerhalb des UserControl an das Control weitergeben und das für die jeweilige Textbox. Ich stelle mir das ungefähr wie in den paar 
    Codezeilen vor, habe aber keinen Ansatz.

    Danke und Gruß
    Gerhard Ahrens

    <MyUserControl x:Name="ucInput"
    Validation.ErrorTemplate="{StaticResource TextBoxErrorTemplate}">
    <MyUserControl.TextBox1>

    <Binding Mode="TwoWay" Path="Description" UpdateSourceTrigger="PropertyChanged"> <Binding.ValidationRules> <validRule:FieldRequired /> </Binding.ValidationRules> </Binding> </MyUserControl.TextBox1> </MyUserControl>


    Donnerstag, 17. Oktober 2013 19:33

Antworten

  • Hallo,
    ich habe es nochmal getestet und konnte keine "großen" Probleme feststellen. Die Änderungen habe ich kommentiert und Fett formatiert:
        public partial class UserControl1 : UserControl
        {
            public UserControl1()
            {
                this.Rules = new ObservableCollection<ValidationRule>();
                this.Rules.CollectionChanged += Rules_CollectionChanged;
                InitializeComponent();
            }
            void Rules_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
            {
    if(this.Rules == null)
    return;//Null zugewiesen? Binding binding = BindingOperations.GetBindingExpression(tb2, TextBox.TextProperty).ParentBinding;//Bindung abrufen binding.ValidationRules.Clear(); //! Zuerst alle alten löschen foreach (var rule in this.Rules) binding.ValidationRules.Add(rule); //sender abfragen bringt nicht, wenn man es nicht benutzt.
    //foreach läuft nicht ann wenn es keine Elemente gibt. } public ObservableCollection<ValidationRule> Rules { get; set; } }
    Das Design:
    <UserControl x:Class="WpfApplication27.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:l="clr-namespace:WpfApplication27"
                 mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300">
        <Grid>
            <TextBox Name="tb1" HorizontalAlignment="Left" Height="23" Margin="22,86,0,0" TextWrapping="Wrap" Text="xyz" VerticalAlignment="Top" Width="120"/>
            <TextBox HorizontalAlignment="Left" Height="23" Margin="38,173,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Name="tb2">
                <Binding UpdateSourceTrigger="PropertyChanged" Path="Text" ElementName="tb1" ValidatesOnDataErrors="True" ValidatesOnExceptions="True"/>
            </TextBox>
        </Grid>
    </UserControl>
    
    Getestet habe ich das hinzufügen der Regel im Codebehind:
                // uc = UserControl
                // AgeRangeRule = Regelklasse
                this.uc.Rules.Add(new AgeRangeRule());
    und im XAML:
            <l:UserControl1 Margin="50" x:Name="uc">
                <l:UserControl1.Rules>
                    <l:AgeRangeRule/>
                </l:UserControl1.Rules>
            </l:UserControl1>
    Ich habe keine Probleme damit.

    Koopakiller [kuːpakɪllɐ] (Tom Lambert)
    Webseite | Code Beispiele | Facebook | Twitter | Snippets   C# ↔ VB.NET Konverter
    Markiert bitte beantwortende Posts als Antwort und bewertet Beiträge. Danke.

    • Als Antwort markiert Gerhard Ahrens Dienstag, 29. Oktober 2013 09:59
    Dienstag, 22. Oktober 2013 13:57
    Moderator

Alle Antworten


  • Hallo,
    Ich denke mal, das es dem Endverwender gestattet sein wird eine ganze Liste an Regeln zu übergeben. Darum brauchst du schonmal eine Auflistung im Codebehind.

            ObservableCollection<ValidationRule> Rules { get; set; }

    Die ObservableCollection kann man auch ohne implementation von INotifyPropertyChanged o.ä. binden.
    Die ValidationRules-Eigenschaft beherscht das leider nicht. Eigenschaften der Regeln selbst sind ebenfalls nicht bind-bar. Somit wird dir wohl nichts anderes Übrig bleiben, als beim verändern der Liste die Regeln der Bindung zu aktualisieren. Da hilft das CollectionChanged-Event.

    In meinem Test probierte ich es ohne UserControl, sondern nur mit dem Fenster, was aber keinen Unterschied machen sollte:

            public MainWindow()
            {
                InitializeComponent();
                this.Rules = new ObservableCollection<ValidationRule>();
                this.Rules.CollectionChanged += Rules_CollectionChanged;
            }
    
            void Rules_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
            {
                Binding binding = BindingOperations.GetBindingExpression(tb2, TextBox.TextProperty).ParentBinding;//Bindung abrufen
                foreach (var rule in this.Rules)
                    binding.ValidationRules.Add(rule);
    
            }
    
            ObservableCollection<ValidationRule> Rules { get; set; }
    
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                this.Rules.Add(new AgeRangeRule());
            }



    Koopakiller [kuːpakɪllɐ] (Tom Lambert)
    Webseite | Code Beispiele | Facebook | Twitter | Snippets   C# ↔ VB.NET Konverter
    Markiert bitte beantwortende Posts als Antwort und bewertet Beiträge. Danke.

    Donnerstag, 17. Oktober 2013 20:10
    Moderator
  • Hallo,

    danke für den Hinweis, ich den C# Source kann ich das hart verpacken, funktioniert auch, nun habe ich ja aber ein allgemeines Control und will die Validierung über den XAML weitergeben. Wie sieht dann der XAML dazu aus ?

    Danke und Gruß

    Gerhard Ahrens

    Freitag, 18. Oktober 2013 12:43
  • Genauso wie bei der normalen Auflistung von Regeln:
    <l:UserControl1 >
        <l:UserControl1.Rules>
            <ExceptionValidationRule />
            <!-- Und noch mehr Regeln... -->
        </l:UserControl1.Rules>
    </l:UserControl1>



    Koopakiller [kuːpakɪllɐ] (Tom Lambert)
    Webseite | Code Beispiele | Facebook | Twitter | Snippets   C# ↔ VB.NET Konverter
    Markiert bitte beantwortende Posts als Antwort und bewertet Beiträge. Danke.

    Freitag, 18. Oktober 2013 13:58
    Moderator
  • Hallo,

    das klappt nicht so richtig.

    Bei aufrufen der Anweisung "Binding binding = BindingOperations...." bekomme ich einen Null-Referenzfehler. Die Rule-Klasse selbst ist in Ordnung. Die Textbox auch. Es sieht mir stark nach einem Problem mit "GetBindingExpression(this.autoTextBox, TextBox.TextProperty).ParentBinding" aus. Hast du hierzu noch eine Idee? Gibt es da womöglich unterschiede im FW. Ich arbeite mit dem FW 4.0. Oder es gibt doch einen Unterschied zwischen einem Window oder UserControl.

    Gruß

    Gerhard Ahrens

    private void Rules_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) {
                if (sender != null) {
                    if (this.Rules != null && this.Rules.Count > 0) {
                        Binding binding = BindingOperations.GetBindingExpression(this.autoTextBox, TextBox.TextProperty).ParentBinding;
                        foreach (var rule in this.Rules) {
                            binding.ValidationRules.Add(rule);
                        }
                    }
                }
    
            }

    Dienstag, 22. Oktober 2013 09:49
  • Hallo,
    ich habe es nochmal getestet und konnte keine "großen" Probleme feststellen. Die Änderungen habe ich kommentiert und Fett formatiert:
        public partial class UserControl1 : UserControl
        {
            public UserControl1()
            {
                this.Rules = new ObservableCollection<ValidationRule>();
                this.Rules.CollectionChanged += Rules_CollectionChanged;
                InitializeComponent();
            }
            void Rules_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
            {
    if(this.Rules == null)
    return;//Null zugewiesen? Binding binding = BindingOperations.GetBindingExpression(tb2, TextBox.TextProperty).ParentBinding;//Bindung abrufen binding.ValidationRules.Clear(); //! Zuerst alle alten löschen foreach (var rule in this.Rules) binding.ValidationRules.Add(rule); //sender abfragen bringt nicht, wenn man es nicht benutzt.
    //foreach läuft nicht ann wenn es keine Elemente gibt. } public ObservableCollection<ValidationRule> Rules { get; set; } }
    Das Design:
    <UserControl x:Class="WpfApplication27.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:l="clr-namespace:WpfApplication27"
                 mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300">
        <Grid>
            <TextBox Name="tb1" HorizontalAlignment="Left" Height="23" Margin="22,86,0,0" TextWrapping="Wrap" Text="xyz" VerticalAlignment="Top" Width="120"/>
            <TextBox HorizontalAlignment="Left" Height="23" Margin="38,173,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Name="tb2">
                <Binding UpdateSourceTrigger="PropertyChanged" Path="Text" ElementName="tb1" ValidatesOnDataErrors="True" ValidatesOnExceptions="True"/>
            </TextBox>
        </Grid>
    </UserControl>
    
    Getestet habe ich das hinzufügen der Regel im Codebehind:
                // uc = UserControl
                // AgeRangeRule = Regelklasse
                this.uc.Rules.Add(new AgeRangeRule());
    und im XAML:
            <l:UserControl1 Margin="50" x:Name="uc">
                <l:UserControl1.Rules>
                    <l:AgeRangeRule/>
                </l:UserControl1.Rules>
            </l:UserControl1>
    Ich habe keine Probleme damit.

    Koopakiller [kuːpakɪllɐ] (Tom Lambert)
    Webseite | Code Beispiele | Facebook | Twitter | Snippets   C# ↔ VB.NET Konverter
    Markiert bitte beantwortende Posts als Antwort und bewertet Beiträge. Danke.

    • Als Antwort markiert Gerhard Ahrens Dienstag, 29. Oktober 2013 09:59
    Dienstag, 22. Oktober 2013 13:57
    Moderator
  • Hallo,

    erstmal Danke für Deine Super Unterstützung. bei mir funktioniert es nun auch.

    Ich hatte es mit der WatermarkTextBox aus der WPF Toolkit Extended versucht. In dieser Konstellation kommt es dann auch die dem Null-Referenzfehler beim Aufruf der "GetBindingExpression()-Methode". Mit einer normalen TextBox funktioniert es. Jetzt noch sozusagen die Kür. Wie bekomme ich nun ein Error-Controltemplete durch das UserControl an meine TextBox ?

    Danke und Gruß
    Gerhard Ahrens

    Mittwoch, 23. Oktober 2013 08:22