IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Attribute sur Property


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2003
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2003
    Messages : 224
    Par défaut Attribute sur Property
    Bonjour,

    j'ai trois classes comme celles-ci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    // Objet business
        public class Customer
        {
            public String firstName {get; set;}
            public String lastName {get; set;}
            public int age {get; set;}
            public String sens { get; set; }
        }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    // Classe abstraite generique me permettant de factoriser le code pour implementer les interfaces IDataErrorInfo et INotifyPropertyChanged 
    public abstract class GenericControler<T> : IDataErrorInfo, INotifyPropertyChanged where T : new()
        {
    (...) // methodes pour IDataErrorInfo et INotifyPropertyChanged 
    #region Generic Controler
            protected T baseObject {get; set;}
     
            public GenericControler()
            {
                baseObject = new T();
            }
     
            public abstract string validate(string propertyName);
     
            #endregion
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
     
    // La classe controler concrete
    public class CustomerControler : GenericControler<Customer>
        {
           public String FirstName
            {
                get { return baseObject.firstName; }
                set {
                    baseObject.firstName = value;
                    this.OnPropertyChanged(new PropertyChangedEventArgs("First Name"));
                }
            }
     
            public String LastName
            {
                get { return baseObject.lastName; }
                set {
                    baseObject.lastName = value;
                    this.OnPropertyChanged(new PropertyChangedEventArgs("Last Name"));
                 }
            }
     
            public int Age
            {
                get { return baseObject.age; }
                set { baseObject.age = value;
                    this.OnPropertyChanged(new PropertyChangedEventArgs("Age"));           
                }
            }
     
            public String Sens
            {
                get { return baseObject.sens; }
                set { baseObject.sens = value;
                    this.OnPropertyChanged(new PropertyChangedEventArgs("Sens"));
                }
            }
    (...)
    et je voudrais arriver à ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class CustomerControler : GenericControler<Customer>
        {
           [objectReference(baseObject.firstName, "FirstName")]
           public String FirstName {get; set;}
     
            [objectReference(baseObject.lastName, "LastName")]
            public String LastName {get; set;}
     
           [objectReference(baseObject.age, "Age")]
            public int Age {get; set;}
     
           [objectReference(baseObject.sens, "Sens")]
            public String Sens {get; set;}
            }
    L'idée étant que mon attribut m'évite d'écrire pour chaque Property
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     set { baseObject.attribut = value;
                    this.OnPropertyChanged(new PropertyChangedEventArgs("Attribut"));           
                }
    Est-ce possible? Si oui comment?

    Je suis preneur de tout autre moyen de m'eviter à écrire le dernier bout de code pour chacun des attributs de ma classe business dans la classe controler representant ma classe business

    C'est exactement ce qu'explique databinding avancé sauf que je comprends rien au tuto..
    donc si qqun pouvait juste me montrer au moins une piste du bout de code necessaire, ce serait cool

  2. #2
    Expert confirmé
    Avatar de Skyounet
    Homme Profil pro
    Software Engineer
    Inscrit en
    Mars 2005
    Messages
    6 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Software Engineer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 6 380
    Par défaut
    Nop j'ai jamais rien vu de tel même si j'avoue que ce serait super pratique.

    C'est à toi de déclencher l'évènement quand ta prop est modifiée.

    En général on passe plutôt par une méthode

    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    private void NotifyPropertyChanged(string propertyName)
    {
       if(PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2003
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2003
    Messages : 224
    Par défaut
    pourtant dans le lien en exemple, il semble utilisé RealProxy pour faire ce genre de chose. mais qd je regarde le code, ca ressemble tellement à une usine à gaz que ca me fait un peu peur..

  4. #4
    Membre Expert Avatar de Guulh
    Homme Profil pro
    Inscrit en
    Septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2007
    Messages : 2 160
    Par défaut
    Le fait de devoir filer le nom de la propriété sous forme de chaîne de caractère est quelque chose qui turlupine les codeurs C# depuis des lustres
    J'étais tombé sur des articles comme celui-ci : http://davybrion.com/blog/2009/08/re...opertychanged/ qui utilisent les Expression<T> dans une classe de base, et dont les classes filles peuvent avoir :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public string MyString
            {
                get
                {
                    return myString;
                }
                set
                {
                    myString = value;
                    NotifyPropertyChanged(t => t.MyString);
                }
            }
    C'est là qu'on voit que les macros du style __LINE__ ou __FUNCTION__ de C++ manquent à C#

  5. #5
    Membre chevronné
    Profil pro
    Inscrit en
    Février 2003
    Messages
    311
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2003
    Messages : 311
    Par défaut
    On peut également faire ça avec PostSharp apparemment

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2003
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2003
    Messages : 224
    Par défaut
    Merci de m'avoir orienté vers PostSharp

    En m inspirant très très largement de ce post sur le forum de PostSharp

    Ca donne ceci:
    Pour créer l'attribut NotifyPropertyChanged
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    #region Released to Public Domain by Gael Fraiteur
    /*----------------------------------------------------------------------------*
     *   This file is part of samples of PostSharp.                                *
     *                                                                             *
     *   This sample is free software: you have an unlimited right to              *
     *   redistribute it and/or modify it.                                         *
     *                                                                             *
     *   This sample is distributed in the hope that it will be useful,            *
     *   but WITHOUT ANY WARRANTY; without even the implied warranty of            *
     *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                      *
     *                                                                             *
     *----------------------------------------------------------------------------*/
    #endregion
     
    using System;
    using System.ComponentModel;
    using System.Reflection;
    using PostSharp.Extensibility;
    using PostSharp.Laos;
     
    namespace PostSharp.Samples.Binding
    {
        /// <summary>
        /// Custom attribute that, when applied on a type (designated <i>target type</i>), implements the interface
        /// <see cref="INotifyPropertyChanged"/> and raises the <see cref="INotifyPropertyChanged.PropertyChanged"/>
        /// event when any property of the target type is modified.
        /// </summary>
        /// <remarks>
        /// Event raising is implemented by appending logic to the <b>set</b> accessor of properties. The 
        /// <see cref="INotifyPropertyChanged.PropertyChanged"/> is raised only when accessors successfully complete.
        /// </remarks>
        [MulticastAttributeUsage( MulticastTargets.Class | MulticastTargets.Struct )]
        [Serializable]
        public sealed class NotifyPropertyChangedAttribute : CompoundAspect
        {
            [NonSerialized] private int aspectPriority = 0;
     
            /// <summary>
            /// Method called at compile time to get individual aspects required by the current compound
            /// aspect.
            /// </summary>
            /// <param name="targetElement">Metadata element (<see cref="Type"/> in our case) to which
            /// the current custom attribute instance is applied.</param>
            /// <param name="collection">Collection of aspects to which individual aspects should be
            /// added.</param>
            public override void ProvideAspects( object targetElement, LaosReflectionAspectCollection collection )
            {
                // Get the target type.
                Type targetType = (Type) targetElement;
     
                // On the type, add a Composition aspect to implement the INotifyPropertyChanged interface.
                collection.AddAspect( targetType, new AddNotifyPropertyChangedInterfaceSubAspect() );
     
                // Add a OnMethodBoundaryAspect on each writable non-static property.
                foreach ( PropertyInfo property in targetType.UnderlyingSystemType.GetProperties() )
                {
                    if ( property.DeclaringType == targetType && property.CanWrite )
                    {
                        MethodInfo method = property.GetSetMethod();
     
                        if ( !method.IsStatic )
                        {
                            collection.AddAspect( method, new OnPropertySetSubAspect( property.Name, this ) );
                        }
                    }
                }
            }
     
            /// <summary>
            /// Gets or sets the priority of the property-level aspect.
            /// </summary>
            /// <remarks>
            /// Give a large number to have the event raisen after any other
            /// on-success aspect on the properties of this type. The default value
            /// is 0.
            /// </remarks>
            public int AspectPriority { get { return aspectPriority; } set { aspectPriority = value; } }
     
     
            /// <summary>
            /// Implementation of <see cref="OnMethodBoundaryAspect"/> that raises the 
            /// <see cref="INotifyPropertyChanged.PropertyChanged"/> event when a property set
            /// accessor completes successfully.
            /// </summary>
            [Serializable]
            internal class OnPropertySetSubAspect : OnMethodBoundaryAspect
            {
                private readonly string propertyName;
     
                /// <summary>
                /// Initializes a new <see cref="OnPropertySetSubAspect"/>.
                /// </summary>
                /// <param name="propertyName">Name of the property to which this set accessor belong.</param>
                /// <param name="parent">Parent <see cref="NotifyPropertyChangedAttribute"/>.</param>
                public OnPropertySetSubAspect( string propertyName, NotifyPropertyChangedAttribute parent )
                {
                    this.AspectPriority = parent.AspectPriority;
                    this.propertyName = propertyName;
                }
     
                /// <summary>
                /// Executed when the set accessor successfully completes. Raises the 
                /// <see cref="INotifyPropertyChanged.PropertyChanged"/> event.
                /// </summary>
                /// <param name="eventArgs">Event arguments with information about the 
                /// current execution context.</param>
                public override void OnSuccess( MethodExecutionEventArgs eventArgs )
                {
                    // Get the implementation of INotifyPropertyChanged. We have access to it through the IComposed interface,
                    // which is implemented at compile time.
                    NotifyPropertyChangedImplementation implementation =
                        (NotifyPropertyChangedImplementation)
                        ( (IComposed<INotifyPropertyChanged>) eventArgs.Instance ).GetImplementation(
                            eventArgs.InstanceCredentials );
     
                    // Raises the PropertyChanged event.
                    implementation.OnPropertyChanged( this.propertyName );
                }
            }
     
            /// <summary>
            /// Implementation of <see cref="CompositionAspect"/> that adds the <see cref="INotifyPropertyChanged"/>
            /// interface to the type to which it is applied.
            /// </summary>
            [Serializable]
            internal class AddNotifyPropertyChangedInterfaceSubAspect : CompositionAspect
            {
                /// <summary>
                /// Called at runtime, creates the implementation of the <see cref="INotifyPropertyChanged"/> interface.
                /// </summary>
                /// <param name="eventArgs">Execution context.</param>
                /// <returns>A new instance of <see cref="NotifyPropertyChangedImplementation"/>, which implements
                /// <see cref="INotifyPropertyChanged"/>.</returns>
                public override object CreateImplementationObject( InstanceBoundLaosEventArgs eventArgs )
                {
                    return new NotifyPropertyChangedImplementation( eventArgs.Instance );
                }
     
                /// <summary>
                /// Called at compile-time, gets the interface that should be publicly exposed.
                /// </summary>
                /// <param name="containerType">Type on which the interface will be implemented.</param>
                /// <returns></returns>
                public override Type GetPublicInterface( Type containerType )
                {
                    return typeof(INotifyPropertyChanged);
                }
     
                public override Type[] GetProtectedInterfaces(Type containerType)
                {
                    return new Type[] {typeof(IFirePropertyChanged)};
                }
     
                /// <summary>
                /// Gets weaving options.
                /// </summary>
                /// <returns>Weaving options specifying that the implementation accessor interface (<see cref="IComposed{T}"/>)
                /// should be exposed, and that the implementation of interfaces should be silently ignored if they are
                /// already implemented in the parent types.</returns>
                public override CompositionAspectOptions GetOptions()
                {
                    return
                        CompositionAspectOptions.GenerateImplementationAccessor |
                        CompositionAspectOptions.IgnoreIfAlreadyImplemented;
                }
            }
     
            /// <summary>
            /// Implementation of the <see cref="INotifyPropertyChanged"/> interface.
            /// </summary>
            internal class NotifyPropertyChangedImplementation : INotifyPropertyChanged, IFirePropertyChanged
            {
                // Instance that exposes the current implementation.
                private readonly object instance;
     
                /// <summary>
                /// Initializes a new <see cref="NotifyPropertyChangedImplementation"/> instance.
                /// </summary>
                /// <param name="instance">Instance that exposes the current implementation.</param>
                public NotifyPropertyChangedImplementation( object instance )
                {
                    this.instance = instance;
                }
     
                /// <summary>
                /// Event raised when a property is changed on the instance that
                /// exposes the current implementation.
                /// </summary>
                public event PropertyChangedEventHandler PropertyChanged;
     
                /// <summary>
                /// Raises the <see cref="PropertyChanged"/> event. Called by the
                /// property-level aspect (<see cref="AddNotifyPropertyChangedInterfaceSubAspect"/>)
                /// at the end of property set accessors.
                /// </summary>
                /// <param name="propertyName">Name of the changed property.</param>
                public void OnPropertyChanged( string propertyName )
                {
                    if ( this.PropertyChanged != null )
                    {
                        this.PropertyChanged( this.instance, new PropertyChangedEventArgs( propertyName ) );
                    }
                }
            }
        }
    }
    mon controleur generique:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ComponentModel;
     
    namespace WpfApplication_TestValidation
    {
        public abstract class GenericControler<T> : IDataErrorInfo, INotifyPropertyChanged where T : new()
        {
            #region INotifyPropertyChanged Members
     
            public event PropertyChangedEventHandler PropertyChanged;
     
            protected virtual void OnPropertyChanged(string e)
            {
                PropertyChangedEventHandler handler = PropertyChanged;
     
                if (handler != null)
                {
                    handler(this, new PropertyChangedEventArgs(e));
                }
            }
            #endregion
     
            #region IDataErrorInfo Members
     
            public string Error
            {
                get { return this[null]; }
            }
     
            public string this[string propertyName]
            {
                get
                {
                    propertyName = propertyName ?? string.Empty;
                    return validate(propertyName);
                }
            }
            #endregion
     
            #region Generic Controler
            protected T baseObject {get; set;}
     
            public GenericControler()
            {
                baseObject = new T();
            }
     
            public abstract string validate(string propertyName);
     
            #endregion
        }
     
    }
    l'objet business et son controler windows1.xaml.cs
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.ComponentModel;
     
    namespace WpfApplication_TestValidation
    {
        /// <summary>
        /// Interaction logic for Window1.xaml
        /// </summary>
        public partial class Window1 : Window
        {
            CustomerControler baseObject;
     
            public Window1()
            {
                InitializeComponent();
                var lSens = new List<string> { "BUY", "SELL" };
                sens.ItemsSource = lSens;
                sens.SelectedIndex = 0;
                DataContext = baseObject = new CustomerControler();
            }
     
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                String result = baseObject.validate("");
                if (result.Length != 0)
                    MessageBox.Show(result);
                else
                    MessageBox.Show("Je valide!");
            }
        }
     
        public class Customer
        {
            public String firstName {get; set;}
            public String lastName {get; set;}
            public int age {get; set;}
            public String sens { get; set; }
        }
     
     
        [NotifyPropertyChanged(OnPropertyChanged = "OnPropertyChanged")]
        public class CustomerControler : GenericControler<Customer>
        {      
           public String FirstName
            {
                get { return baseObject.firstName; }
                set { baseObject.firstName = value; }
            }
     
            public String LastName
            {
                get { return baseObject.lastName; }
                set { baseObject.lastName = value; }
            }
     
            public int Age
            {
                get { return baseObject.age; }
                set { baseObject.age = value; }
            }
     
            public String Sens
            {
                get { return baseObject.sens; }
                set { baseObject.sens = value; }
            }
     
            public override string validate(string propertyName)
            {
                string result = String.Empty;
                if (propertyName == string.Empty || propertyName == "FirstName")
                {
                    if (string.IsNullOrEmpty(this.FirstName))
                    {
                        result += "First Name is mandatory." + Environment.NewLine;
                    }
                }
     
                if (propertyName == string.Empty || propertyName == "LastName")
                {
                    if (string.IsNullOrEmpty(this.LastName) || this.LastName.Length > 30)
                    {
                        result += "Last Name is mandatory and must be less than 30 letters."
                            + Environment.NewLine;
                    }
                }
     
                if (propertyName == string.Empty || propertyName == "Age")
                {
                    if (string.IsNullOrEmpty(this.Age.ToString()))
                    {
                        result += "Age is mandatory." + Environment.NewLine;
                    }
                    if (this.Age < 10)
                        result += "Too young!" + Environment.NewLine;
                }
     
                if (propertyName == string.Empty || propertyName == "Sens")
                {
                    if (string.IsNullOrEmpty(this.Sens))
                    {
                        result += "Sens is mandatory." + Environment.NewLine;
                    }               
                }
                return result.TrimEnd();
            }
     
        }
     
    }
    Merci à tous.
    Ca marche nickel pour faire du binding avec WPF

    app.xaml
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    <Application x:Class="WpfApplication_TestValidation.App"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:igEditors="http://infragistics.com/Editors"
        StartupUri="Window1.xaml">
        <Application.Resources>
             <Style x:Key="validationStyle" TargetType="{x:Type Control}">
                <Setter Property="Validation.ErrorTemplate">
                    <Setter.Value>
                        <ControlTemplate>
                            <DockPanel LastChildFill="True">
                                <Border BorderBrush="Red" BorderThickness="1">
                                    <AdornedElementPlaceholder />
                                </Border>
                            </DockPanel>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
                <Style.Triggers>
                    <Trigger Property="Validation.HasError" Value="true">
                        <Setter Property="ToolTip"
                    Value="{Binding RelativeSource={RelativeSource Self}, 
                           Path=(Validation.Errors)[0].ErrorContent}"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
            <Style TargetType="{x:Type igEditors:XamComboEditor}" BasedOn="{StaticResource validationStyle}" />  
            <Style TargetType="{x:Type igEditors:XamMaskedEditor}" BasedOn="{StaticResource validationStyle}" />        
        </Application.Resources>
    </Application>
    Windows1.xaml
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    <Window x:Class="WpfApplication_TestValidation.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:igEditors="http://infragistics.com/Editors"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        xmlns:local="clr-namespace:WpfApplication_TestValidation"
        Title="Window1" Height="300" Width="300">
        <Grid>
            <local:ErrorProvider>
                <WrapPanel>
                    <Label>First Name</Label>
                    <igEditors:XamMaskedEditor Text="{Binding Path=FirstName, UpdateSourceTrigger=PropertyChanged}" ValueType="{x:Type sys:String}" Width="90"/>
                    <Label>Last Name</Label>
                    <igEditors:XamMaskedEditor Text="{Binding Path=LastName, UpdateSourceTrigger=PropertyChanged}" ValueType="{x:Type sys:String}" Width="90"/>                   
                    <Label>Age</Label>
                    <igEditors:XamMaskedEditor Text="{Binding Path=Age, UpdateSourceTrigger=PropertyChanged}" ValueType="{x:Type sys:Int32}" Width="90"/>
                    <Label >Sens :</Label>
                    <igEditors:XamComboEditor  Name="sens" Text="{Binding Path=Sens, UpdateSourceTrigger=PropertyChanged}" ValueType="{x:Type sys:String}"  Width="90"/>
                    <Button Click="Button_Click" >Validate</Button>
                </WrapPanel>
            </local:ErrorProvider>
        </Grid>
    </Window>
    errorprovider.cs trouvé je sais plus trop où...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Windows.Controls;
    using System.Windows;
    using System.ComponentModel;
    using System.Windows.Data;
    using System.Reflection;
     
    namespace WpfApplication_TestValidation
    {
        public class ErrorProvider : Decorator
        {
            private delegate void FoundBindingCallbackDelegate(FrameworkElement element, Binding binding, DependencyProperty dp);
            private FrameworkElement _firstInvalidElement;
            private Dictionary<DependencyObject, Style> _backupStyles = new Dictionary<DependencyObject, Style>();
     
            /// <summary>
            /// Constructor.
            /// </summary>
            public ErrorProvider()
            {
                this.DataContextChanged += new DependencyPropertyChangedEventHandler(ErrorProvider_DataContextChanged);
                this.Loaded += new RoutedEventHandler(ErrorProvider_Loaded);
            }
     
            /// <summary>
            /// Called when this component is loaded. We have a call to Validate here that way errors appear from the very 
            /// moment the page or form is visible.
            /// </summary>
            private void ErrorProvider_Loaded(object sender, RoutedEventArgs e)
            {
                Validate();
            }
     
            /// <summary>
            /// Called when our DataContext changes.
            /// </summary>
            private void ErrorProvider_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
            {
                if (e.OldValue != null && e.OldValue is INotifyPropertyChanged)
                {
                    ((INotifyPropertyChanged)e.NewValue).PropertyChanged -= new PropertyChangedEventHandler(DataContext_PropertyChanged);
                }
     
                if (e.NewValue != null && e.NewValue is INotifyPropertyChanged)
                {
                    ((INotifyPropertyChanged)e.NewValue).PropertyChanged += new PropertyChangedEventHandler(DataContext_PropertyChanged);
                }
     
                Validate();
            }
     
            /// <summary>
            /// Validates all properties on the current data source.
            /// </summary>
            /// <returns>True if there are no errors displayed, otherwise false.</returns>
            /// <remarks>
            /// Note that only errors on properties that are displayed are included. Other errors, such as errors for properties that are not displayed, 
            /// will not be validated by this method.
            /// </remarks>
            public bool Validate()
            {
                bool isValid = true;
                _firstInvalidElement = null;
     
                if (this.DataContext is IDataErrorInfo)
                {
                    List<Binding> allKnownBindings = ClearInternal();
     
                    // Now show all errors
                    foreach (Binding knownBinding in allKnownBindings)
                    {
                        string errorMessage = ((IDataErrorInfo)this.DataContext)[knownBinding.Path.Path];
                        if (errorMessage != null && errorMessage.Length > 0)
                        {
                            isValid = false;
     
                            // Display the error on any elements bound to the property
                            FindBindingsRecursively(
                            this.Parent,
                            delegate(FrameworkElement element, Binding binding, DependencyProperty dp)
                            {
                                if (knownBinding.Path.Path == binding.Path.Path)
                                {
     
                                    BindingExpression expression = element.GetBindingExpression(dp);
                                    ValidationError error = new ValidationError(new ExceptionValidationRule(), expression, errorMessage, null);
                                    System.Windows.Controls.Validation.MarkInvalid(expression, error);
     
                                    if (_firstInvalidElement == null)
                                    {
                                        _firstInvalidElement = element;
                                    }
                                    return;
     
                                }
                            });
                        }
                    }
                }
                return isValid;
            }
     
            /// <summary>
            /// Returns the first element that this error provider has labelled as invalid. This method 
            /// is useful to set the users focus on the first visible error field on a page.
            /// </summary>
            /// <returns></returns>
            public FrameworkElement GetFirstInvalidElement()
            {
                return _firstInvalidElement;
            }
     
            /// <summary>
            /// Clears any error messages.
            /// </summary>
            public void Clear()
            {
                ClearInternal();
            }
     
            /// <summary>
            /// Clears any error messages and returns a list of all bindings on the current form/page. This is simply so 
            /// it can be reused by the Validate method.
            /// </summary>
            /// <returns>A list of all known bindings.</returns>
            private List<Binding> ClearInternal()
            {
                // Clear all errors
                List<Binding> bindings = new List<Binding>();
                FindBindingsRecursively(
                        this.Parent,
                        delegate(FrameworkElement element, Binding binding, DependencyProperty dp)
                        {
                            // Remember this bound element. We'll use this to display error messages for each property.
                            bindings.Add(binding);
                        });
                return bindings;
            }
     
            /// <summary>
            /// Called when the PropertyChanged event is raised from the object we are bound to - that is, our data context.
            /// </summary>
            private void DataContext_PropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                if (e.PropertyName == "IsValid")
                {
                    return;
                }
                Validate();
            }
     
            /// <summary>
            /// Recursively goes through the control tree, looking for bindings on the current data context.
            /// </summary>
            /// <param name="element">The root element to start searching at.</param>
            /// <param name="callbackDelegate">A delegate called when a binding if found.</param>
            private void FindBindingsRecursively(DependencyObject element, FoundBindingCallbackDelegate callbackDelegate)
            {
     
                // See if we should display the errors on this element
                MemberInfo[] members = element.GetType().GetMembers(BindingFlags.Static | 
                        BindingFlags.Public |
                        BindingFlags.FlattenHierarchy);
     
                foreach (MemberInfo member in members)
                {
                    DependencyProperty dp = null;
     
                    // Check to see if the field or property we were given is a dependency property
                    if (member.MemberType == MemberTypes.Field)
                    {
                        FieldInfo field = (FieldInfo)member;
                        if (typeof(DependencyProperty).IsAssignableFrom(field.FieldType))
                        {
                            dp = (DependencyProperty)field.GetValue(element);
                        }
                    }
                    else if (member.MemberType == MemberTypes.Property)
                    {
                        PropertyInfo prop = (PropertyInfo)member;
                        if (typeof(DependencyProperty).IsAssignableFrom(prop.PropertyType))
                        {
                            dp = (DependencyProperty)prop.GetValue(element, null);
                        }
                    }
     
                    if (dp != null)
                    {
                        // Awesome, we have a dependency property. does it have a binding? If yes, is it bound to the property we're interested in?
                        Binding bb = BindingOperations.GetBinding(element, dp);
                        if (bb != null)
                        {
                            // This element has a DependencyProperty that we know of that is bound to the property we're interested in. 
                            // Now we just tell the callback and the caller will handle it.
                            if (element is FrameworkElement)
                            {
                                if (((FrameworkElement)element).DataContext == this.DataContext)
                                {
                                    callbackDelegate((FrameworkElement)element, bb, dp);
                                }
                            }
                        }
                    }
                }
     
                // Now, recurse through any child elements
                if (element is FrameworkElement || element is FrameworkContentElement)
                {
                    foreach (object childElement in LogicalTreeHelper.GetChildren(element))
                    {
                        if (childElement is DependencyObject)
                        {
                            FindBindingsRecursively((DependencyObject)childElement, callbackDelegate);
                        }
                    }
                }
            }
        }
    }
    J'utilise la lib graphique infragistics mais ca marche pareil avc les TextBox wpf de base.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. problem de saisie d'attribut sur une jsp
    Par anouss dans le forum Servlets/JSP
    Réponses: 1
    Dernier message: 22/05/2007, 08h35
  2. [XSLT] Récupérer un attribut sur un élément pointé par un IDREF
    Par Folken Laëneck dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 13/05/2007, 07h31
  3. [Xpath] Selection d'attributs sur critère
    Par lolo_ici_et_la dans le forum XSL/XSLT/XPATH
    Réponses: 1
    Dernier message: 22/03/2006, 22h04
  4. [MySQL] [SQLyog] comment ne pas trier les attributs sur 1 PK
    Par raoulmania dans le forum Installation
    Réponses: 11
    Dernier message: 19/12/2005, 16h30
  5. Problème sur property Items de ListBox
    Par Andry dans le forum Langage
    Réponses: 4
    Dernier message: 24/08/2005, 12h10

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo