Bonjour à tous,

J'ai essayé de créer un contrôleur personnalisé pour un élément graphique que je répète plusieurs fois dans une de mes interfaces.

Pour ce faire, j'ai suivi ce tuto (malheureusement encore incomplet) :
http://www.wpftutorial.net/howtocrea...omcontrol.html

J'ai donc créé un projet DataAnalyzerModuleLib dans ma solution avec
- la classe DataAnalyzerModule.cs :
Code C# : 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
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
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.Windows.Controls.Primitives;
using GalaSoft.MvvmLight.Command;
 
namespace DataAnalyzerModuleLib
{
    /// <summary>
    /// Suivez les étapes 1a ou 1b puis 2 pour utiliser ce contrôle personnalisé dans un fichier XAML.
    ///
    /// Étape 1a) Utilisation de ce contrôle personnalisé dans un fichier XAML qui existe dans le projet actif.
    /// Ajoutez cet attribut XmlNamespace à l'élément racine du fichier de balisage où il doit 
    /// être utilisé*:
    ///
    ///     xmlns:MyNamespace="clr-namespace:DataAnalyzerModuleLib"
    ///
    ///
    /// Étape 1b) Utilisation de ce contrôle personnalisé dans un fichier XAML qui existe dans un autre projet.
    /// Ajoutez cet attribut XmlNamespace à l'élément racine du fichier de balisage où il doit 
    /// être utilisé*:
    ///
    ///     xmlns:MyNamespace="clr-namespace:DataAnalyzerModuleLib;assembly=DataAnalyzerModuleLib"
    ///
    /// Vous devrez également ajouter une référence du projet contenant le fichier XAML
    /// à ce projet et régénérer pour éviter des erreurs de compilation*:
    ///
    ///     Cliquez avec le bouton droit sur le projet cible dans l'Explorateur de solutions, puis sur
    ///     "Ajouter une référence"->"Projets"->[Sélectionnez ce projet]
    ///
    ///
    /// Étape 2)
    /// Utilisez à présent votre contrôle dans le fichier XAML.
    ///
    ///     <MyNamespace:CustomControl1/>
    ///
    /// </summary>
    public class DataAnalyzerModule : ItemsControl 
    {
        static DataAnalyzerModule()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(DataAnalyzerModule), new FrameworkPropertyMetadata(typeof(DataAnalyzerModule)));
        }
 
        #region ===== DependencyProperty ==========================================================
 
        #region ***** Value *********************
 
        /// <summary>
        /// Registers a dependency property as backing store for the Value property
        /// </summary>
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(int), typeof(DataAnalyzerModule),
            new FrameworkPropertyMetadata(1,
                  FrameworkPropertyMetadataOptions.AffectsRender |
                  FrameworkPropertyMetadataOptions.AffectsParentMeasure));
 
        /// <summary>
        /// Progress of the data analysis
        /// </summary>
        public int Value
        {
            get { return (int)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }
 
        #endregion
 
        #region ***** Maximum *******************
 
        /// <summary>
        /// Registers a dependency property as backing store for the Maximum property
        /// </summary>
        public static readonly DependencyProperty MaximumProperty =
            DependencyProperty.Register("Maximum", typeof(int), typeof(DataAnalyzerModule),
            new FrameworkPropertyMetadata(1,
                  FrameworkPropertyMetadataOptions.AffectsRender |
                  FrameworkPropertyMetadataOptions.AffectsParentMeasure));
 
        /// <summary>
        /// Maximum progress of the data analysis
        /// </summary>
        public int Maximum
        {
            get { return (int)GetValue(MaximumProperty); }
            set { SetValue(MaximumProperty, value); }
        }
 
        #endregion
 
        #region ***** Abort *********************
 
        /// <summary>
        /// Registers a dependency property as backing store for the Abort property
        /// </summary>
        public static readonly DependencyProperty AbortProperty =
            DependencyProperty.Register("Abort", typeof(RelayCommand), typeof(DataAnalyzerModule),
            new FrameworkPropertyMetadata(null,
                  FrameworkPropertyMetadataOptions.AffectsRender |
                  FrameworkPropertyMetadataOptions.AffectsParentMeasure));
 
        /// <summary>
        /// Abort the data analysis
        /// </summary>
        public RelayCommand Abort
        {
            get { return (RelayCommand)GetValue(AbortProperty); }
            set { SetValue(AbortProperty, value); }
        }
 
        #endregion
 
        #region ***** CountOfItemsByPage ********
 
        /// <summary>
        /// Registers a dependency property as backing store for the CountOfItemsByPage property
        /// </summary>
        public static readonly DependencyProperty CountOfItemsByPageProperty =
            DependencyProperty.Register("CountOfItemsByPage", typeof(int), typeof(DataAnalyzerModule),
            new FrameworkPropertyMetadata(500,
                  FrameworkPropertyMetadataOptions.AffectsRender |
                  FrameworkPropertyMetadataOptions.AffectsParentMeasure));
 
        /// <summary>
        /// Count of displayed items by page
        /// </summary>
        public int CountOfItemsByPage
        {
            get { return (int)GetValue(CountOfItemsByPageProperty); }
            set { SetValue(CountOfItemsByPageProperty, value); }
        }
 
        #endregion
 
        #region ***** GoToFirstPage *************
 
        /// <summary>
        /// Registers a dependency property as backing store for the GoToFirstPage property
        /// </summary>
        public static readonly DependencyProperty GoToFirstPageProperty =
            DependencyProperty.Register("GoToFirstPage", typeof(RelayCommand), typeof(DataAnalyzerModule),
            new FrameworkPropertyMetadata(null,
                  FrameworkPropertyMetadataOptions.AffectsRender |
                  FrameworkPropertyMetadataOptions.AffectsParentMeasure));
 
        /// <summary>Go to the first page</summary>
        private RelayCommand _goToFirstPage;
 
        /// <summary>
        /// Go to the first page
        /// </summary>
        public RelayCommand GoToFirstPage
        {
            get
            {
                if (_goToFirstPage == null) _goToFirstPage = new RelayCommand(() => PageIndex = 1, () => PageIndex > 1);
                return _goToFirstPage;
            }
        }
 
        #endregion
 
        #region ***** GoToPreviousPage **********
 
        /// <summary>
        /// Registers a dependency property as backing store for the GoToPreviousPage property
        /// </summary>
        public static readonly DependencyProperty GoToPreviousPageProperty =
            DependencyProperty.Register("GoToPreviousPage", typeof(RelayCommand), typeof(DataAnalyzerModule),
            new FrameworkPropertyMetadata(null,
                  FrameworkPropertyMetadataOptions.AffectsRender |
                  FrameworkPropertyMetadataOptions.AffectsParentMeasure));
 
        /// <summary>Go to previous page</summary>
        private RelayCommand _goToPreviousPage;
 
        /// <summary>
        /// Go to previous page.
        /// </summary>
        public RelayCommand GoToPreviousPage
        {
            get
            {
                if (_goToPreviousPage == null) _goToPreviousPage = new RelayCommand(() => PageIndex--, () => PageIndex > 1);
                return _goToPreviousPage;
            }
        }
 
        #endregion
 
        #region ***** PageIndex *****************
 
        /// <summary>
        /// Registers a dependency property as backing store for the PageIndex property
        /// </summary>
        public static readonly DependencyProperty PageIndexProperty =
            DependencyProperty.Register("PageIndex", typeof(int), typeof(DataAnalyzerModule),
            new FrameworkPropertyMetadata(1,
                  FrameworkPropertyMetadataOptions.AffectsRender |
                  FrameworkPropertyMetadataOptions.AffectsParentMeasure));
 
        /// <summary>
        /// Gets or sets the page index.
        /// </summary>
        public int PageIndex
        {
            get { return (int)GetValue(PageIndexProperty); }
            set { SetValue(PageIndexProperty, value); }
        }
 
        #endregion
 
        #region ***** CountOfPage ***************
 
        /// <summary>
        /// Registers a dependency property as backing store for the CountOfPage property
        /// </summary>
        public static readonly DependencyProperty CountOfPageProperty =
            DependencyProperty.Register("CountOfPage", typeof(int), typeof(DataAnalyzerModule),
            new FrameworkPropertyMetadata(1,
                  FrameworkPropertyMetadataOptions.AffectsRender |
                  FrameworkPropertyMetadataOptions.AffectsParentMeasure));
 
        /// <summary>
        /// Gets the count of page.
        /// </summary>
        public int CountOfPage
        {
            get { return (int)GetValue(CountOfPageProperty); }
            set { SetValue(CountOfPageProperty, value); }
        }
 
        #endregion
 
        #region ***** GoToNextPage **************
 
        /// <summary>
        /// Registers a dependency property as backing store for the GoToNextPage property
        /// </summary>
        public static readonly DependencyProperty GoToNextPageProperty =
            DependencyProperty.Register("GoToNextPage", typeof(RelayCommand), typeof(DataAnalyzerModule),
            new FrameworkPropertyMetadata(null,
                  FrameworkPropertyMetadataOptions.AffectsRender |
                  FrameworkPropertyMetadataOptions.AffectsParentMeasure));
 
        /// <summary>Go to next page</summary>
        private RelayCommand _goToNextPage;
 
        /// <summary>
        /// Go to next page.
        /// </summary>
        public RelayCommand GoToNextPage
        {
            get
            {
                if (_goToNextPage == null) _goToNextPage = new RelayCommand(() => PageIndex++, () => PageIndex < CountOfPage);
                return _goToNextPage;
            }
        }
 
        #endregion
 
        #region ***** GoToLastPage **************
 
        /// <summary>
        /// Registers a dependency property as backing store for the GoToLastPage property
        /// </summary>
        public static readonly DependencyProperty GoToLastPageProperty =
            DependencyProperty.Register("GoToLastPage", typeof(RelayCommand), typeof(DataAnalyzerModule),
            new FrameworkPropertyMetadata(null,
                  FrameworkPropertyMetadataOptions.AffectsRender |
                  FrameworkPropertyMetadataOptions.AffectsParentMeasure));
 
        /// <summary>Go to last page</summary>
        private RelayCommand _goToLastPage;
 
        /// <summary>
        /// Go to last page.
        /// </summary>
        public RelayCommand GoToLastPage
        {
            get
            {
                if (_goToLastPage == null) _goToLastPage = new RelayCommand(() => PageIndex = CountOfPage, () => PageIndex < CountOfPage);
                return _goToLastPage;
            }
        }
 
        #endregion
 
        #endregion
    }
}

- le code XAML Themes/Generic.xaml :
Code xaml : 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
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:DataAnalyzerModuleLib"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WPF4">
 
    <Style TargetType="{x:Type ProgressBar}" x:Key="ProgressBarStyle">
        <Setter Property="Foreground">
            <Setter.Value>
                <SolidColorBrush Color="DeepSkyBlue"/>
            </Setter.Value>
        </Setter>
        <Setter Property="Background">
            <Setter.Value>
                <SolidColorBrush Color="White"/>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate>
                    <Grid Margin="1">
                        <Rectangle x:Name="opacityMask" RadiusX="0" RadiusY="0" Fill="{TemplateBinding Background}" Margin="0"/>
                        <Grid Margin="-1">
                            <Grid.OpacityMask>
                                <VisualBrush Visual="{Binding ElementName=opacityMask}"/>
                            </Grid.OpacityMask>
                            <Rectangle x:Name="PART_Track" RadiusX="{Binding ElementName=opacityMask, Path=RadiusX}" RadiusY="{Binding ElementName=opacityMask, Path=RadiusY}" Stroke="{TemplateBinding BorderBrush}" StrokeThickness="0" Fill="{TemplateBinding Background}"/>
                            <Rectangle x:Name="PART_Indicator" RadiusX="{Binding ElementName=opacityMask, Path=RadiusX}" RadiusY="{Binding ElementName=opacityMask, Path=RadiusY}" Stroke="{TemplateBinding BorderBrush}" StrokeThickness="0" HorizontalAlignment="Left" Fill="{TemplateBinding Foreground}" />
                        </Grid>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style TargetType="{x:Type local:DataAnalyzerModule}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:DataAnalyzerModule}">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition/>
                            <RowDefinition Height="Auto"/>
                        </Grid.RowDefinitions>
                        <!--Barre de progression-->
                        <ProgressBar Height="7" Value="{TemplateBinding Value}" Maximum="{TemplateBinding Maximum}" Style="{StaticResource ProgressBarStyle}"/>
                        <!--Bouton annuler-->
                        <Grid Background="Transparent">
                            <Grid.Style>
                                <Style TargetType="{x:Type Grid}">
                                    <Style.Triggers>
                                        <Trigger Property="IsMouseOver" Value="False">
                                            <Setter Property="Opacity" Value="0"></Setter>
                                        </Trigger>
                                        <Trigger Property="IsMouseOver" Value="True">
                                            <Setter Property="Opacity" Value="1"></Setter>
                                        </Trigger>
                                    </Style.Triggers>
                                </Style>
                            </Grid.Style>
 
                            <Image Source="/LecteurSegy2G;component/Images/Exit.bmp" HorizontalAlignment="Right" Height="7" Margin="0">
                                <i:Interaction.Triggers>
                                    <i:EventTrigger EventName="MouseLeftButtonUp">
                                        <cmd:EventToCommand Command="{TemplateBinding Abort}"/>
                                    </i:EventTrigger>
                                </i:Interaction.Triggers>
                            </Image>
                        </Grid>
 
                        <ListView Grid.Row="1" Height="15" ItemsSource="{TemplateBinding ItemsSource}" ItemTemplate="{TemplateBinding ItemTemplate}"
                                  ItemsPanel="{TemplateBinding ItemsPanel}"><!--SelectedItem="{TemplateBinding SelectedItem}"-->
                        </ListView>
 
                        <!--Manipulation des pages-->
                        <StackPanel Orientation="Horizontal" Grid.Row="2" HorizontalAlignment="Right">
                            <TextBlock TextWrapping="Wrap" Text="Nb élément par page" Width="65" TextAlignment="Right"/>
                            <TextBox Text="{TemplateBinding CountOfItemsByPage}" Margin="2,0,0,0" VerticalContentAlignment="Center"/>
                            <Button Content="&lt;&lt;" Margin="2,0,0,0" Command="{TemplateBinding GoToFirstPage}"/>
                            <Button Content="&lt;" Command="{TemplateBinding GoToPreviousPage}"/>
                            <TextBox Text="{TemplateBinding PageIndex}" Margin="2,0,0,0" VerticalContentAlignment="Center"/>
                            <TextBlock Text="/" Margin="2,0,0,0" VerticalAlignment="Center"/>
                            <TextBlock Text="{TemplateBinding CountOfPage}" Margin="2,0,0,0" VerticalAlignment="Center"/>
                            <Button Content="&gt;" Margin="2,0,0,0" Command="{TemplateBinding GoToNextPage}"/>
                            <Button Content="&gt;&gt;" Command="{TemplateBinding GoToLastPage}"/>
                        </StackPanel>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

Je l'appelle ensuite dans ma solution :
Code xaml : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
 
<!--...-->
      xmlns:daml="clr-namespace:DataAnalyzerModuleLib;assembly=DataAnalyzerModuleLib"
<!--...-->
                <daml:DataAnalyzerModule Value="10" Maximum="50" Margin="5"/>
<!--...-->

Je remarque dans mon designer que la progressbar n'a pas les valeurs "10" et "50" que j'ai arbitrairement mises dans le dernier code présenté et qu'elle n'a pas non plus les valeurs par défaut définies dans les dependency properties (DataAnalyzerModule.cs)
Nom : governingFrameworkElement.PNG
Affichages : 169
Taille : 3,1 Ko

Mon application se lance sans problèmes apparents mais j'obtient le message suivant dans la console :
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element.
BindingExpressionno path); DataItem=null; target element is 'VisualBrush' (HashCode=64454972); target property is 'Visual' (type 'Visual')
et le DataAnalyzerModule inséré n'a pas les valeurs par défauts et le code ne passe pas par les "get" de mes depndencyProperties...