Rectangle.Fill et ImageBrush n'affichent rien
Bonjour,
Je souhaite remplir mon rectangle avec une image.
Code:
1 2 3 4 5
| <Rectangle Height="80" Width="80" Stroke="{StaticResource SquareBorder}" RadiusY="5" RadiusX="5">
<Rectangle.Fill>
<ImageBrush x:Name="Content" ImageSource="/Images/MonImage.png"/>
</Rectangle.Fill>
</Rectangle> |
Dans le designer de VS ou de Blend, l'image s'affiche parfaitement bien dans le rectangle.
Or, dans IE, mon image ne s'affiche pas...
Cependant, si je remplace mon image par une couleur, la couleur s'affiche sous IE.
Quelqu'un a une idée ?
Merci de votre aide,
Steven
Mon expérience avec les images et autres médias
Lorsque l’on parle d’une Uri relative, à quoi est-elle relative ?
Au fichier XMAL/VB/C# dans lequel le lien se trouve. La réponse parait simple mais elle mérite attention.- Cela change nos habitude car nous sommes souvent plus familliés avec les Uri relatives au site Web
- L'écriture de nos Uri dépend de la position de nos fichier XAML/VB/C#
Actions de génération (Build Action)
L’explorateur de propriété permet de définir une ‘action de génération’ pour chaque fichier. Par défaut, lorsque l’on intègre une image dans un projet Silverlight, l’action de génération est ‘Ressource’.
Trois types d’action de génération sont à retenir :
- Ressource (Resource)
- Contenu (Content)
- Aucun (None)
En imaginant que :
- le nom de l’assembly est ‘Test’ (Pour retrouver le nom, voir dans les propriétés du projet, onglet Silverlight).
- Le nom du fichier est ‘monimage.jpg’
- Que le fichier est dans un dossier ‘Images’ (un dossier dans le projet, pas un dossier dans le site Web).
Si action de génération = Ressource
Le fichier sera inclus dans l’assembly en tant que ressource.
Dans ce cas, un simple chemin relatif à la ressource suffit parfois (par relatif il faut entendre, relatif à la position du fichier XAML/VB/C# dans lequel est utilisé l’Uri). Mais cela peut très vite devenir compliqué surtout si vous créez et utilisez des contrôles (utilisateurs ou non). Je vous recommande donc les syntaxes suivantes.
Uri en XAML :
Code:
"Test;component/Images/monimage.jpg"
Uri en c# :
Code:
Uri("Test;component/Images/Saisie_ monimage.png", UriKind.Relative);
Note : Cette façon de procéder permet en fait de toujours écrire des Uri relatives à la racine de l’assembly.
Si action de génération = Contenu
Le fichier sera inclus dans le XAP. Dans notre exemple, cela implique q’un dossier ‘Images’ sera créé dans le XAP (qui pour le rappeler n’est en fait qu’un fichier zip), et que le fichier ‘monimage.jpg’ y sera placée.
Dans ce cas, les syntaxes suivantes peuvent être utilisées.
Uri en XAML :
Code:
"/Images/monimage.jpg"
Uri en c# :
Code:
new Uri("/Images/monimage.png", UriKind.Relative);
Note : Notez la présence du ‘/’ en début d’Uri. Cette fois ci, l’Uri est relative à la racine du fichier XAP.
Si action de génération = Aucun
Dans ce cas, en plus de définir ‘action de génération’, définissez aussi ‘Copier dans le répertoire de sortie’. Le fichier sera copié dans ClientBin.
Les syntaxes suivantes peuvent être utilisées.
Uri en XAML :
Code:
"/Images/monimage.jpg"
Uri en c# :
Code:
new Uri("/Images/monimage.png", UriKind.Relative);
Note : J’ai plusieurs fois eu des soucis de copie de fichiers non effectués avec cette méthode. Je préfère généralement copier moi-même mes fichiers dans le site Web (dans ClientBin), sans les inclure dans le projet Silverlight.
Note : Vous remarquerez que la syntaxe pour accéder à un fichier dans le XAP ou dans le ClientBin est la même. En cas de conflit de nom, c’est le XAP qui gagne.
Note : Pour remonter l’arborescence du site Web en amont de ClientBin, il faut utiliser une Uri absolue. Le mieux c’est de la construire via le code en utilisant
Code:
Application.Current.Host.Source.AbsolutePath
Conclusion
Cette description demande sans doute à être complètée, je suis preneur de toute nouvelle info.
Chargement dynamique d'un package
On peut dire que vous avez de la chance. Je suis en plein dedant car je suis en train de préparer une formation Silverlight avancé. J'ai donc pris quelques instants pour vous rédiger une classe implémentant un mécanisme permettant le chargement dynamique d'un package (xap ou zip). Il ne s'agit que d'une implémentation de base, cela prendrait trop de temps pour présenter toutes les implications et techniques, à vous d'imaginer les reste.
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
|
/// <summary>
/// Classe permetant le chargement dynamique d'un package
/// </summary>
public class Package
{
private string _PackageRelativeUri = null;
private System.IO.Stream _PackageStream = null;
/// <summary>
/// Evènement appelé après le chargement
/// </summary>
public event EventHandler<EventArgs> Loaded = null;
/// <summary>
/// Instanciation.
/// </summary>
/// <param name="PackageRelativeUri">Uri relative du package par rapport au XAP principal.</param>
public Package(string PackageRelativeUri)
{
_PackageRelativeUri = PackageRelativeUri;
}
/// <summary>
/// Déclanchement du chargement. Abonnez-vous à Loaded avant d'appeler cette méthode.
/// </summary>
public void Load()
{
Uri uri = new Uri(_PackageRelativeUri, UriKind.Relative);
WebClient webClient = new WebClient();
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(Load_Completed);
webClient.OpenReadAsync(uri);
}
private void Load_Completed(object sender, OpenReadCompletedEventArgs e)
{
_PackageStream = e.Result;
if (Loaded != null) Loaded(this, new EventArgs());
}
/// <summary>
/// Retourne vrai si le package est chargé.
/// </summary>
public bool IsReady
{
get { return _PackageStream != null; }
}
/// <summary>
/// Retourne un flux pour une ressource donnée.
/// </summary>
/// <param name="PackageRelativeUriString">Uri relative de la resource, par rapport au package.</param>
/// <returns>Flux</returns>
public System.IO.Stream GetStream(string RelativeUriString)
{
if (IsReady)
{
Uri uri = new Uri(RelativeUriString, UriKind.Relative);
var ri = new System.Windows.Resources.StreamResourceInfo(_PackageStream, null);
var rs = Application.GetResourceStream(ri, uri);
if(rs!=null) return rs.Stream;
throw new Exception(string.Format("La ressource '{1}' est introuvable dans le package '{0}'.", _PackageRelativeUri, RelativeUriString));
}
throw new Exception(string.Format("La package '{0}' n'est pas chargé.", _PackageRelativeUri));
}
/// <summary>
/// Retourne une image pour une ressource donnée.
/// </summary>
/// <param name="relativeUriString">Uri relative de la resource, par rapport au package.</param>
/// <returns>Image</returns>
public Image GetImage(string relativeUriString)
{
var bi = new System.Windows.Media.Imaging.BitmapImage();
bi.SetSource(GetStream(relativeUriString));
return new Image() { Source = bi };
}
} |
Voici comment exploiter cette classe.
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
|
private Package MonPackage = null;
private void Button_Click(object sender, RoutedEventArgs e)
{
//---> Création du Package, il doit référencer, de façon relative
// au XAP principal, soit un fichier .zip, soit un fichier .xap
// (rappelons qu'un .xap peut être vu comme .zip dont l'extension
// a été changée). Ce fichier .zip contient autant de fichiers
// que voulu, de tout type, organisés en dossiers et sous dossiers
// si besoin est.
MonPackage = new Package("MonPackage.zip");
//---> On s'abonne à l'évènement qui sera appelé quand le chargement
// du package sera terminé
MonPackage.Loaded += new EventHandler<EventArgs>(MonPackage_Loaded);
//---> On déclanche le chargement
MonPackage.Load();
}
void MonPackage_Loaded(object sender, EventArgs e)
{
//---> Le package est chargé, nous pouvons accéder
// à son contenu. Dans mon exemple, mon package ne contient
// qu'un dossier 'Images' et dans se dossier se trouve un
// fichier 'about.png'
this.Content = MonPackage.GetImage("Images/about.png");
} |
Il existe plusieurs autres méthodes. J'ai présenté celle qui me parait la plus simple, d'autant qu'il suffit de réutiliser la classe Package. Il est de façon similaire, possible de charger synamiquement des Assemblies et ensuite d'instancier les objets qu'elles contiennent.
Quoi qu'il en soit, Silverlight c'est puissant.