Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 9 sur 9
  1. #1
    Membre chevronné Avatar de yonpo
    Homme Profil pro Antoine
    Développeur .NET
    Inscrit en
    mars 2010
    Messages
    602
    Détails du profil
    Informations personnelles :
    Nom : Homme Antoine
    Âge : 25
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : mars 2010
    Messages : 602
    Points : 768
    Points
    768

    Par défaut Propriété attachée - FlowDocument WPF

    Salut,

    Je propose une nouvelle classe à ajouter (je l'espère ) au projet dvp.net :
    Elle permet, via une propriété attachée, de binder la propriété Blocks d'un FlowDocument à une collection (List<Block> par exemple).

    Code c# :
    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
    /// <summary>
        /// Permet d'effectuer une liaison de données sur la propriété Blocks d'un FlowDocument
        /// </summary>
        public static class FlowDocumentBehavior
        {
            /// <summary>
            /// Obtient la valeur de la propriété attachée BindableBlocks pour l'objet spécifié
            /// </summary>
            /// <param name="obj">Objet dont on souhaite obtenir la valeur de la propriété</param>
            /// <returns></returns>
            public static IEnumerable<Block> GetBindableBlocks(DependencyObject obj)
            {
                return (IEnumerable<Block>)obj.GetValue(BindableBlocksProperty);
            }
     
            /// <summary>
            /// Définit la valeur de la propriété attachée BindableBlocks pour l'objet spécifié
            /// </summary>
            /// <param name="obj">Objet dont on souhaite définir la valeur de la propriété</param>
            /// <param name="value">Valeur de la propriété de dépendance spécifiée</param>
            public static void SetBindableBlocks(DependencyObject obj, IEnumerable<Block> value)
            {
                obj.SetValue(BindableBlocksProperty, value);
            }
     
            /// <summary>
            /// Propriété attachée BindableBlocks
            /// </summary>
            public static readonly DependencyProperty BindableBlocksProperty =
                DependencyProperty.RegisterAttached("BindableBlocks",
                typeof(IEnumerable<Block>), typeof(FlowDocumentBehavior), new UIPropertyMetadata(null, BindableBlocksChanged));
     
            private static void BindableBlocksChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
            {
                if (dependencyObject is FlowDocument)
                {
                    var obj = dependencyObject as FlowDocument;
                    obj.Blocks.Clear();
                    if (e.NewValue != null)
                    {
                        foreach (var block in (IEnumerable<Block>)e.NewValue)
                        {
                            obj.Blocks.Add(block);
                        }
                    }
                }
            }
        }
    Gérer vos mangas en ligne ? C'est ici

  2. #2
    Rédacteur/Modérateur



    Homme Profil pro Thomas Levesque
    Développeur .NET
    Inscrit en
    février 2004
    Messages
    19 204
    Détails du profil
    Informations personnelles :
    Nom : Homme Thomas Levesque
    Âge : 33
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : février 2004
    Messages : 19 204
    Points : 36 687
    Points
    36 687

    Par défaut

    Bonne idée

    Juste une petite remarque : ce serait bien de gérer le cas où la collection bindée implémente INotifyCollectionChanged, de façon à ce que les éléments ajoutés ensuite à la collection soient ajoutés au FlowDocument

  3. #3
    Membre chevronné Avatar de yonpo
    Homme Profil pro Antoine
    Développeur .NET
    Inscrit en
    mars 2010
    Messages
    602
    Détails du profil
    Informations personnelles :
    Nom : Homme Antoine
    Âge : 25
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : mars 2010
    Messages : 602
    Points : 768
    Points
    768

    Par défaut

    Voici la classe modifiée :

    Code c# :
    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
    /// <summary>
        /// Permet d'effectuer une liaison de données sur la propriété Blocks d'un FlowDocument
        /// </summary>
        public static class FlowDocumentBehavior
        {
            private static FlowDocument _flowDocument;
     
            /// <summary>
            /// Obtient la valeur de la propriété attachée BindableBlocks pour l'objet spécifié
            /// </summary>
            /// <param name="obj">Objet dont on souhaite obtenir la valeur de la propriété</param>
            /// <returns></returns>
            public static IEnumerable<Block> GetBindableBlocks(DependencyObject obj)
            {
                return (IEnumerable<Block>)obj.GetValue(BindableBlocksProperty);
            }
     
            /// <summary>
            /// Définit la valeur de la propriété attachée BindableBlocks pour l'objet spécifié
            /// </summary>
            /// <param name="obj">Objet dont on souhaite définir la valeur de la propriété</param>
            /// <param name="value">Valeur de la propriété de dépendance spécifiée</param>
            public static void SetBindableBlocks(DependencyObject obj, IEnumerable<Block> value)
            {
                obj.SetValue(BindableBlocksProperty, value);
            }
     
            /// <summary>
            /// Propriété attachée BindableBlocks
            /// </summary>
            public static readonly DependencyProperty BindableBlocksProperty =
                DependencyProperty.RegisterAttached("BindableBlocks",
                typeof(IEnumerable<Block>), typeof(FlowDocumentBehavior), new UIPropertyMetadata(null, BindableBlocksChanged));
     
            private static void BindableBlocksChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
            {
                _flowDocument = dependencyObject as FlowDocument;
     
                if (_flowDocument == null) return;
     
                _flowDocument.Blocks.Clear();
                if (e.NewValue != null)
                {
                    var newValue = (IEnumerable<Block>)e.NewValue;
                    foreach (var block in newValue)
                    {
                        _flowDocument.Blocks.Add(block);
                    }
     
                    var observableList = newValue as INotifyCollectionChanged;
                    if (observableList != null) observableList.CollectionChanged += BlocksCollectionChanged;
                }
            }
     
            private static void BlocksCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
            {
                if (e.OldItems != null)
                {
                    foreach (Block item in e.OldItems)
                    {
                        _flowDocument.Blocks.Remove(item);
                    }
                }
     
                if (e.NewItems != null)
                {
                    foreach (Block item in e.NewItems)
                    {
                        _flowDocument.Blocks.Add(item);
                    }
                }
            }
        }
    Gérer vos mangas en ligne ? C'est ici

  4. #4
    Rédacteur/Modérateur



    Homme Profil pro Thomas Levesque
    Développeur .NET
    Inscrit en
    février 2004
    Messages
    19 204
    Détails du profil
    Informations personnelles :
    Nom : Homme Thomas Levesque
    Âge : 33
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : février 2004
    Messages : 19 204
    Points : 36 687
    Points
    36 687

    Par défaut

    Bah non, tu peux pas faire comme ça... si tu stockes le FlowDocument dans un champ statique de la classe, ça fait que tu ne peux jamais utiliser plus d'un FlowDocument dans ton programme. Il faut trouver une autre solution...

    Une possibilité est de créer une classe spécifique pour gérer la "synchronisation" entre la collection et le FlowDocument, et de stocker un objet de cette classe dans une autre propriété attachée (privée et en lecture seule), pour l'associer au FlowDocument.

  5. #5
    Membre chevronné Avatar de yonpo
    Homme Profil pro Antoine
    Développeur .NET
    Inscrit en
    mars 2010
    Messages
    602
    Détails du profil
    Informations personnelles :
    Nom : Homme Antoine
    Âge : 25
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : mars 2010
    Messages : 602
    Points : 768
    Points
    768

    Par défaut

    Ah oui... Bien vue !

    Je regarderai ça.
    Gérer vos mangas en ligne ? C'est ici

  6. #6
    Membre chevronné Avatar de yonpo
    Homme Profil pro Antoine
    Développeur .NET
    Inscrit en
    mars 2010
    Messages
    602
    Détails du profil
    Informations personnelles :
    Nom : Homme Antoine
    Âge : 25
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : mars 2010
    Messages : 602
    Points : 768
    Points
    768

    Par défaut

    J'ai corrigé le code en m'aspirant de tes remarques :

    Code c# :
    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
    /// <summary>
        /// Permet d'effectuer une liaison de données sur la propriété Blocks d'un FlowDocument
        /// </summary>
        public static class FlowDocumentBehavior
        {
            /// <summary>
            /// Obtient la valeur de la propriété attachée BindableBlocks pour l'objet spécifié
            /// </summary>
            /// <param name="obj">Objet dont on souhaite obtenir la valeur de la propriété</param>
            /// <returns></returns>
            public static IEnumerable<Block> GetBindableBlocks(DependencyObject obj)
            {
                return (IEnumerable<Block>)obj.GetValue(BindableBlocksProperty);
            }
     
            /// <summary>
            /// Définit la valeur de la propriété attachée BindableBlocks pour l'objet spécifié
            /// </summary>
            /// <param name="obj">Objet dont on souhaite définir la valeur de la propriété</param>
            /// <param name="value">Valeur de la propriété de dépendance spécifiée</param>
            public static void SetBindableBlocks(DependencyObject obj, IEnumerable<Block> value)
            {
                obj.SetValue(BindableBlocksProperty, value);
            }
     
            /// <summary>
            /// Propriété attachée BindableBlocks
            /// </summary>
            public static readonly DependencyProperty BindableBlocksProperty =
                DependencyProperty.RegisterAttached("BindableBlocks",
                typeof(IEnumerable<Block>), typeof(FlowDocumentBehavior), new UIPropertyMetadata(null, BindableBlocksChanged));
     
            private static void BindableBlocksChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
            {
                var flowDocument = dependencyObject as FlowDocument;
     
                if (flowDocument == null) return;
     
                if (e.NewValue != null)
                {
                    var sync = new FlowDocumentSync(flowDocument, (IEnumerable<Block>)e.NewValue);
                    SetFlowDocumentSync(flowDocument, sync);
                }
            }
     
            private static FlowDocumentSync GetFlowDocumentSync(DependencyObject obj)
            {
                return (FlowDocumentSync)obj.GetValue(_flowDocumentSyncPropertyKey.DependencyProperty);
            }
     
            private static void SetFlowDocumentSync(DependencyObject obj, FlowDocumentSync value)
            {
                obj.SetValue(_flowDocumentSyncPropertyKey, value);
            }
     
            private static readonly DependencyPropertyKey _flowDocumentSyncPropertyKey =
                DependencyProperty.RegisterAttachedReadOnly("flowDocumentSync",
                typeof(FlowDocumentSync), typeof(FlowDocumentBehavior), new UIPropertyMetadata(null));
        }
     
        internal class FlowDocumentSync
        {
            private FlowDocument _flowDocument;
            private IEnumerable<Block> _blocks;
     
            public FlowDocumentSync(FlowDocument flowDocument, IEnumerable<Block> blocks)
            {
                _flowDocument = flowDocument;
                _blocks = blocks;
     
                _flowDocument.Blocks.Clear();
     
                foreach (var block in _blocks)
                {
                    _flowDocument.Blocks.Add(block);
                }
     
                var observableList = _blocks as INotifyCollectionChanged;
                if (observableList != null) observableList.CollectionChanged += BlocksCollectionChanged;
            }
     
            private void BlocksCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
            {
                if (e.OldItems != null)
                {
                    foreach (Block item in e.OldItems)
                    {
                        _flowDocument.Blocks.Remove(item);
                    }
                }
     
                if (e.NewItems != null)
                {
                    foreach (Block item in e.NewItems)
                    {
                        _flowDocument.Blocks.Add(item);
                    }
                }
            }
        }

    J'ai testé avec deux collections bindés sur deux FlowDocument et ça fonctionne (ajout, suppression d'éléments).
    Gérer vos mangas en ligne ? C'est ici

  7. #7
    Rédacteur/Modérateur



    Homme Profil pro Thomas Levesque
    Développeur .NET
    Inscrit en
    février 2004
    Messages
    19 204
    Détails du profil
    Informations personnelles :
    Nom : Homme Thomas Levesque
    Âge : 33
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : février 2004
    Messages : 19 204
    Points : 36 687
    Points
    36 687

    Par défaut

    C'est à peu près ce que j'avais en tête

    Par contre, encore un petit truc qui ne va pas : tu ne te désabonnes pas de l'évènement CollectionChanged quand la propriété BindableBlocks change, ce qui peut causer des fuites mémoires (voire des bugs si l'ancienne collection est modifiée alors même qu'elle n'est plus bindée)

    Il faudrait faire quelque chose comme ça :

    Code :
    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
        /// <summary>
        /// Permet d'effectuer une liaison de données sur la propriété Blocks d'un FlowDocument
        /// </summary>
        public static class FlowDocumentBehavior
        {
            /// <summary>
            /// Obtient la valeur de la propriété attachée BindableBlocks pour l'objet spécifié
            /// </summary>
            /// <param name="obj">Objet dont on souhaite obtenir la valeur de la propriété</param>
            /// <returns></returns>
            public static IEnumerable<Block> GetBindableBlocks(DependencyObject obj)
            {
                return (IEnumerable<Block>)obj.GetValue(BindableBlocksProperty);
            }
     
            /// <summary>
            /// Définit la valeur de la propriété attachée BindableBlocks pour l'objet spécifié
            /// </summary>
            /// <param name="obj">Objet dont on souhaite définir la valeur de la propriété</param>
            /// <param name="value">Valeur de la propriété de dépendance spécifiée</param>
            public static void SetBindableBlocks(DependencyObject obj, IEnumerable<Block> value)
            {
                obj.SetValue(BindableBlocksProperty, value);
            }
     
            /// <summary>
            /// Propriété attachée BindableBlocks
            /// </summary>
            public static readonly DependencyProperty BindableBlocksProperty =
                DependencyProperty.RegisterAttached("BindableBlocks",
                typeof(IEnumerable<Block>), typeof(FlowDocumentBehavior), new UIPropertyMetadata(null, BindableBlocksChanged));
     
            private static void BindableBlocksChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
            {
                var flowDocument = dependencyObject as FlowDocument;
     
                if (flowDocument == null) return;
     
                // Désabonnement de l'ancienne collection
                if (e.OldValue != null)
                {
                    var sync = GetFlowDocumentSync(flowDocument);
                    if (sync != null)
                    {
                        sync.Dispose();
                        SetFlowDocumentSync(flowDocument, null);
                    }
                }
     
                if (e.NewValue != null)
                {
                    var sync = new FlowDocumentSync(flowDocument, (IEnumerable<Block>)e.NewValue);
                    SetFlowDocumentSync(flowDocument, sync);
                }
            }
     
            private static FlowDocumentSync GetFlowDocumentSync(DependencyObject obj)
            {
                return (FlowDocumentSync)obj.GetValue(_flowDocumentSyncPropertyKey.DependencyProperty);
            }
     
            private static void SetFlowDocumentSync(DependencyObject obj, FlowDocumentSync value)
            {
                obj.SetValue(_flowDocumentSyncPropertyKey, value);
            }
     
            private static readonly DependencyPropertyKey _flowDocumentSyncPropertyKey =
                DependencyProperty.RegisterAttachedReadOnly("flowDocumentSync",
                typeof(FlowDocumentSync), typeof(FlowDocumentBehavior), new UIPropertyMetadata(null));
        }
     
        internal class FlowDocumentSync : IDisposable
        {
            private FlowDocument _flowDocument;
            private IEnumerable<Block> _blocks;
     
            public FlowDocumentSync(FlowDocument flowDocument, IEnumerable<Block> blocks)
            {
                _flowDocument = flowDocument;
                _blocks = blocks;
     
                _flowDocument.Blocks.Clear();
     
                foreach (var block in _blocks)
                {
                    _flowDocument.Blocks.Add(block);
                }
     
                var observableList = _blocks as INotifyCollectionChanged;
                if (observableList != null) observableList.CollectionChanged += BlocksCollectionChanged;
            }
     
            private void BlocksCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
            {
                if (e.OldItems != null)
                {
                    foreach (Block item in e.OldItems)
                    {
                        _flowDocument.Blocks.Remove(item);
                    }
                }
     
                if (e.NewItems != null)
                {
                    foreach (Block item in e.NewItems)
                    {
                        _flowDocument.Blocks.Add(item);
                    }
                }
            }
     
            public void Dispose()
            {
                var observableList = _blocks as INotifyCollectionChanged;
                if (observableList != null) observableList.CollectionChanged -= BlocksCollectionChanged;
            }
        }
    Sinon j'aurais aussi déclaré la classe FlowDocumentSync dans la classe FlowDocumentBehavior, mais ça change pas grand chose

    Je fais quelques tests et j'intègre ça à Dvp.NET

  8. #8
    Membre chevronné Avatar de yonpo
    Homme Profil pro Antoine
    Développeur .NET
    Inscrit en
    mars 2010
    Messages
    602
    Détails du profil
    Informations personnelles :
    Nom : Homme Antoine
    Âge : 25
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : mars 2010
    Messages : 602
    Points : 768
    Points
    768

    Par défaut

    Ok, super !
    Merci pour tes propositions qui ont permis d'améliorer la classe et qui m'ont aussi appris quelques trucs.

    Je mettrai quand ça sera intégré au projet.
    Gérer vos mangas en ligne ? C'est ici

  9. #9
    Rédacteur/Modérateur



    Homme Profil pro Thomas Levesque
    Développeur .NET
    Inscrit en
    février 2004
    Messages
    19 204
    Détails du profil
    Informations personnelles :
    Nom : Homme Thomas Levesque
    Âge : 33
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : février 2004
    Messages : 19 204
    Points : 36 687
    Points
    36 687

    Par défaut

    C'est intégré, ce sera dans la prochaine release ( pas de date prévue pour l'instant)

    Merci pour ta contribution

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

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •