Bonjour,
Je dispose d'une liste de noms (mais ici, ce sera "1", "2", "3",...) et pour certains, d'une image correspondante ("1png", "3.png",...)
Selon que j'image correspondante soit disponible ou pas, je voulais pouvoir afficher dans un control (et pas nécessairement une liste) l'image OU le texte!
J'ai penser à un ItemsControl avec un DataTemplate et un DataTemplateSelector et suis parvenu à ce résultat:
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 <Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication1" Title="MainWindow" Height="350" Width="525" Background="#FF3A3A48"> <Grid Name="mainGrid"> <Grid.Resources> <local:RelativeToAbsolutePathConverter x:Key="relToAbsPathConverter" /> <DataTemplate x:Key="stringTemplate"> <TextBlock Text="{Binding}" HorizontalAlignment="Center" Foreground="Beige"/> </DataTemplate> <DataTemplate x:Key="imageTemplate"> <Image Source="{Binding Converter={StaticResource relToAbsPathConverter}}"/> </DataTemplate> <local:ImgStringTemplateSelector ImageTemplate="{StaticResource imageTemplate}" StringTemplate="{StaticResource stringTemplate}" x:Key="imgStringTemplateSelector" /> </Grid.Resources> <ItemsControl ScrollViewer.CanContentScroll="False" Name="ItemsControl1" ItemTemplateSelector="{StaticResource imgStringTemplateSelector}" Margin="0,0,134,0"> <ItemsControl.ItemContainerStyle> <Style> <Setter Property="Control.Height" Value="25"/> <Setter Property="Control.Margin" Value="4"/> </Style> </ItemsControl.ItemContainerStyle> </ItemsControl> <Button Content="Up" Height="23" HorizontalAlignment="Left" Margin="399,244,0,0" Name="Button1" VerticalAlignment="Top" Width="75" /> </Grid> </Window>
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 Class MainWindow Dim displayedItems As Integer = 9 Dim displayed As New List(Of logos) Private Sub MainWindow_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles Me.Loaded ' Create List displayed.Add(New logos With {.Name = "1"}) displayed.Add(New logos With {.Name = "2"}) displayed.Add(New logos With {.Name = "3"}) displayed.Add(New logos With {.Name = "4"}) displayed.Add(New logos With {.Name = "5"}) displayed.Add(New logos With {.Name = "6"}) displayed.Add(New logos With {.Name = "7"}) displayed.Add(New logos With {.Name = "8"}) displayed.Add(New logos With {.Name = "9"}) displayed.Add(New logos With {.Name = "10"}) displayed.Add(New logos With {.Name = "11"}) displayed.Add(New logos With {.Name = "12"}) displayed.Add(New logos With {.Name = "13"}) displayed.Add(New logos With {.Name = "14"}) displayed.Add(New logos With {.Name = "15"}) displayed.Add(New logos With {.Name = "16"}) ' Populate ItemsControl For i As Integer = 0 To displayedItems - 1 ItemsControl1.Items.Add(displayed(i).Name) Next End Sub Private Sub Button1_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles Button1.Click For i As Integer = 0 To displayedItems - 1 ItemsControl1.Items(i) = displayed(i + 1).Name Next End Sub End Class Public Class logos Private _name As String Public Property Name() As String Get Return _name End Get Set(value As String) _name = value End Set End Property End Class Public Class RelativeToAbsolutePathConverter Implements IValueConverter Public Function Convert(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.Convert Dim relative As [String] = TryCast(value, String) If relative Is Nothing Then Return Nothing End If Return System.AppDomain.CurrentDomain.BaseDirectory & "Logos\" & relative & ".png" End Function Public Function ConvertBack(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.ConvertBack Throw New NotImplementedException() End Function End Class Public Class ImgStringTemplateSelector Inherits DataTemplateSelector Public Property ImageTemplate() As DataTemplate Get Return m_ImageTemplate End Get Set(value As DataTemplate) m_ImageTemplate = value End Set End Property Private m_ImageTemplate As DataTemplate Public Property StringTemplate() As DataTemplate Get Return m_StringTemplate End Get Set(value As DataTemplate) m_StringTemplate = value End Set End Property Private m_StringTemplate As DataTemplate Public Overrides Function SelectTemplate(item As Object, container As DependencyObject) As DataTemplate Dim path As String = DirectCast(item, String) If System.IO.File.Exists(System.AppDomain.CurrentDomain.BaseDirectory & "Logos\" & path & ".png") Then Return ImageTemplate End If Return StringTemplate End Function End Class
Donc, j'envoie du texte à l'ItemsControl et si il y a une image disponible avec ce nom il affiche l'image, sinon il affiche le texte!
Seulement j'ai un problème: quand je veux modifier le contenu des Items de l'ItemsControl (par l'appui sur le bouton) j'ai l'erreur suivante:
System.Windows.Data Error: 6 : 'DynamicValueConverter' converter failed to convert value 'C:\Users\jmd_000\Desktop\Demande forum\TestGridDisplayedItem\bin\Debug\Logos\4.png' (type 'String'); fallback value will be used, if available. BindingExpressionath=; DataItem='String' (HashCode=-842352756); target element is 'Image' (Name=''); target property is 'Source' (type 'ImageSource') FileNotFoundException:'System.IO.FileNotFoundException: Le fichier 'C:\Users\jmd_000\Desktop\Demande forum\TestGridDisplayedItem\bin\Debug\Logos\4.png' est introuvable.
Nom de fichier : 'C:\Users\jmd_000\Desktop\Demande forum\TestGridDisplayedItem\bin\Debug\Logos\4.png'
...contrairement à ce que j'imaginais il n'y a pas d'update du DataTemplateSelector et l'application se plaint de ne pas trouver d'image pour un item dont le DataTemplate est toujours une image, alors qu'il devrait être du texte! (j'espère que je suis clair dans mes explication!!? ;-) )
J'aurais donc besoin de votre aide sur ces points:
1) Si je reste sur cette logique, comment puis-je forcer la ré-évaluation par le DataTemplateSelector qu'il doit appeler un template texte ou image? (trigger?)
2) En réalité, je n'ai pas du tout besoin d'une 'liste'..dans l'idéal les objets devraient être disséminés sur la page et je préfèrerais avoir des ContentControl qui se comporteraient de la même façon, c'est à dire adapter leur template selon que l'image soit disponible ou pas. Mais comme les objets doivent impérativement être créés dynamiquement, j'ignore comment attacher un DataTemplateSelector (et ses DataTemplate) par le code uniquement! Pourriez-vous m'aider pour cela? (Et le problème de la ré-évaluation par le DataTemplateSelector se poserait-il à nouveau?)
3) Globalement, quelle est la meilleur façon de créer un conteneur, qui peut recevoir texte ou image et adapter sa présentation en fonction, et être mis-à jour?
Un grand merci pour m'avoir lu et pour l'aide que vous voudrez bien m'apporter!!
(Toute aide est la bienvenue, même en C#)
Voici le lien vers le projet VS
http://www87.zippyshare.com/v/Ai28XH5A/file.html
Partager