Précédent   Forum du club des développeurs et IT Pro > Dotnet > Général Dotnet > Contribuez
Contribuez Proposez vos articles, cours, tutoriels, faq, sources pour .NET
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 23/07/2012, 14h54   #1
yonpo
Membre émérite
 
Avatar de yonpo
 
Homme Antoine
Développeur .NET
Inscription : mars 2010
Messages : 586
Détails du profil
Informations personnelles :
Nom : Homme Antoine
Âge : 24
Localisation : France

Informations professionnelles :
Activité : Développeur .NET
Secteur : Industrie

Informations forums :
Inscription : mars 2010
Messages : 586
Points : 835
Points : 835
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);
                    }
                }
            }
        }
    }
__________________
Un logiciel pour gérer vos mangas ? C'est ici
yonpo est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 29/07/2012, 15h34   #2
tomlev
Rédacteur/Modérateur


 
Avatar de tomlev
 
Homme Thomas Levesque
Développeur .NET
Inscription : février 2004
Messages : 17 770
Détails du profil
Informations personnelles :
Nom : Homme Thomas Levesque
Âge : 31
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 : 17 770
Points : 33 998
Points : 33 998
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
__________________

Pas de questions techniques par MP ! Le forum est là pour ça...

Tutoriels : Les markup extensions en WPF - La sérialisation XML avec .NET (Aller plus loin) - Une visite guidée de WPF (traduction)
Projet : Dvp.NET, la librairie .NET open-source des membres de Developpez !
tomlev est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 31/07/2012, 09h39   #3
yonpo
Membre émérite
 
Avatar de yonpo
 
Homme Antoine
Développeur .NET
Inscription : mars 2010
Messages : 586
Détails du profil
Informations personnelles :
Nom : Homme Antoine
Âge : 24
Localisation : France

Informations professionnelles :
Activité : Développeur .NET
Secteur : Industrie

Informations forums :
Inscription : mars 2010
Messages : 586
Points : 835
Points : 835
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);
                }
            }
        }
    }
__________________
Un logiciel pour gérer vos mangas ? C'est ici
yonpo est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 31/07/2012, 15h06   #4
tomlev
Rédacteur/Modérateur


 
Avatar de tomlev
 
Homme Thomas Levesque
Développeur .NET
Inscription : février 2004
Messages : 17 770
Détails du profil
Informations personnelles :
Nom : Homme Thomas Levesque
Âge : 31
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 : 17 770
Points : 33 998
Points : 33 998
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.
__________________

Pas de questions techniques par MP ! Le forum est là pour ça...

Tutoriels : Les markup extensions en WPF - La sérialisation XML avec .NET (Aller plus loin) - Une visite guidée de WPF (traduction)
Projet : Dvp.NET, la librairie .NET open-source des membres de Developpez !
tomlev est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 31/07/2012, 16h03   #5
yonpo
Membre émérite
 
Avatar de yonpo
 
Homme Antoine
Développeur .NET
Inscription : mars 2010
Messages : 586
Détails du profil
Informations personnelles :
Nom : Homme Antoine
Âge : 24
Localisation : France

Informations professionnelles :
Activité : Développeur .NET
Secteur : Industrie

Informations forums :
Inscription : mars 2010
Messages : 586
Points : 835
Points : 835
Ah oui... Bien vue !

Je regarderai ça.
__________________
Un logiciel pour gérer vos mangas ? C'est ici
yonpo est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/08/2012, 09h45   #6
yonpo
Membre émérite
 
Avatar de yonpo
 
Homme Antoine
Développeur .NET
Inscription : mars 2010
Messages : 586
Détails du profil
Informations personnelles :
Nom : Homme Antoine
Âge : 24
Localisation : France

Informations professionnelles :
Activité : Développeur .NET
Secteur : Industrie

Informations forums :
Inscription : mars 2010
Messages : 586
Points : 835
Points : 835
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).
__________________
Un logiciel pour gérer vos mangas ? C'est ici
yonpo est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/08/2012, 11h29   #7
tomlev
Rédacteur/Modérateur


 
Avatar de tomlev
 
Homme Thomas Levesque
Développeur .NET
Inscription : février 2004
Messages : 17 770
Détails du profil
Informations personnelles :
Nom : Homme Thomas Levesque
Âge : 31
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 : 17 770
Points : 33 998
Points : 33 998
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
__________________

Pas de questions techniques par MP ! Le forum est là pour ça...

Tutoriels : Les markup extensions en WPF - La sérialisation XML avec .NET (Aller plus loin) - Une visite guidée de WPF (traduction)
Projet : Dvp.NET, la librairie .NET open-source des membres de Developpez !
tomlev est actuellement connecté   Envoyer un message privé Réponse avec citation 10
Vieux 02/08/2012, 13h29   #8
yonpo
Membre émérite
 
Avatar de yonpo
 
Homme Antoine
Développeur .NET
Inscription : mars 2010
Messages : 586
Détails du profil
Informations personnelles :
Nom : Homme Antoine
Âge : 24
Localisation : France

Informations professionnelles :
Activité : Développeur .NET
Secteur : Industrie

Informations forums :
Inscription : mars 2010
Messages : 586
Points : 835
Points : 835
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.
__________________
Un logiciel pour gérer vos mangas ? C'est ici
yonpo est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 02/08/2012, 23h12   #9
tomlev
Rédacteur/Modérateur


 
Avatar de tomlev
 
Homme Thomas Levesque
Développeur .NET
Inscription : février 2004
Messages : 17 770
Détails du profil
Informations personnelles :
Nom : Homme Thomas Levesque
Âge : 31
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 : 17 770
Points : 33 998
Points : 33 998
C'est intégré, ce sera dans la prochaine release ( pas de date prévue pour l'instant)

Merci pour ta contribution
__________________

Pas de questions techniques par MP ! Le forum est là pour ça...

Tutoriels : Les markup extensions en WPF - La sérialisation XML avec .NET (Aller plus loin) - Une visite guidée de WPF (traduction)
Projet : Dvp.NET, la librairie .NET open-source des membres de Developpez !
tomlev est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Réponse Cette discussion est résolue.
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 09h56.


 
 
 
 
Partenaires

Hébergement Web