Benutzer mit den meisten Antworten
Bild, wie "verstecken"

Frage
-
Hallo,
Meine Frage handelt dieses mal wie kann ich Bilder verstauen, dass sie beim kompilieren keinen Ordner anlegen aber jederzeit benutzt werden können?
Als Beispiel: Ich habe 2 Bilder. Wenn ich auf Button1 klicke soll Bild1 in einem Grid angezeigt werden. Wenn ich Button2 klicke soll Bild2 im Grid angezeigt werden. Ich möchte das ganze aber nicht mit der GetFullPath Methode, da ich den Usern keinen Zugriff auf die direkten Bilder geben möchte, lediglich nur eine "Skinfunktion" um dadurch das Aussehen des Programms zu ändern.
Der Gedanke hinter dieser Idee ist folgender: Ich mache einen Layout Ordner und lese immer wenn benötigt ein Design mit der GetFullPath Methode aus. Wenn nun ein User jedoch den Namen ändert, wäre keine Imagesource mehr vorhanden und das Bild kann nicht angezeigt werden. Wenn ich nun irgendwie die Bilder aus Ressourcen anzeigen lassen kann, wenn sie benötigt werden, kann dies nicht passieren.
Hier ein Beispiel noch wie ich es geschrieben habe, jedoch NICHT möchte:
ImageBrush myBrush = new ImageBrush(); myBrush.ImageSource = new BitmapImage(new Uri(list1.Find(f => f.id == 1).source.ToString())); grid1.Background = myBrush;
Zur Erklärung dieses Codes: list1 greift indem Fall auf eine Klasse zu und sucht aus der Itemliste von id=1 den Imagesource raus.
Was es mir eben etwas verschwert ist, dass ich den Imagesource in der Klasse abspeichern muss, da ich dadurch weiß, welches Item welche ID hat, wenn das ganze aber nun irgendwie in einer Ressourcedatei ist habe ich relativ wenig Ahnung, wie ich dies in meine Klasse schreiben muss um dies auch zum laufen zu bringen.
Dazu noch meine Klasse:
public List<Items> Weapons() { List<Items> weapons = new List<Items>(); weapons.Add(new Items() { id = 1, name = "Katana", attack = 20, speed = 10, dodge = 15, tip = "With this Katana do you slay everything!", source = path + "//Sword1.png" }); return weapons; } public string name { get; set; } public int id { get; set; } public int attack { get; set; } public int hitpoints { get; set; } public int defense { get; set; } public int speed { get; set; } public string tip { get; set; } public string source { get; set; }
EDIT: Mir ist klar, das in der Klasse Weapons steht obwohl nur eine Waffe hinzu gefügt wird. Weitere Waffen füge ich ein sobald mein Code passt. Ebenfalls ist mein Code nur zum testen. Den Code schreibe ich natürlich dann passend um.
Mit freundlichen Grüßen
Markus Ö.
- Bearbeitet Bashesz Samstag, 14. Juni 2014 22:05
- Typ geändert Tom Lambert (Koopakiller)Moderator Sonntag, 15. Juni 2014 13:11 Frage
Antworten
-
Hallo zusammen,
warum sich das laden eines Bildes in WPF so schwer machen?image.Source = new BitmapImage(new Uri(@"/myimg.png", UriKind.Relative));
Das erzeugte BitmapImage kannst du überall in WPF einbringen, wo ein Bild benötigt wird. Ein Problem mit Transparenz gibt es da eigentlich nicht. Wenn doch, poste bitte einen Screenshot davon.
Auch auf eine RESX-Datei würde ich versuchen unter WPF zu verzichten, die bringt dir eigentlich keine Vorteile.
Wie viele Bilder hat denn jede Waffe? Wenn jede Waffe nur ein Bild hat, kannst du einfach eine ImageSource-Eigenschaft in der Weapons-Klasse erstellen und diese beim initialisieren zuweisen. Wenn es ein 3D-Modell o.ä. gibt, kannst du auch eine eigene Klasse anlegen, die sämtliche Bilder enthält und eine Instanz dieser Klasse in Weapons einfügen.
An deiner Stelle würde ich eine XML-Datei o.ä. verwenden um alle Waffen mit ihren Initialisierungswerten abzuspeichern. Darin kannst du auch den Namen des Bildes abspeichern. Beim starten des Spiels kannst du nun die Datei auslesen und dynamisch jede Waffe erstellen und zu deiner Liste hinzufügen.
<?xml version="1.0" encoding="utf-8" ?> <Weapons> <Weapon Id="0" Name="Waffe 1" Attack="1" Speed="10" Image="/Images/Image1.png"></Weapon> <Weapon Id="1" Name="Waffe 2" Attack="2" Speed="15" Image="/Images/Image2.png"></Weapon> <Weapon Id="2" Name="Waffe 3" Attack="5" Speed="20" Image="/Images/Image3.png"></Weapon> </Weapons>
Diese Datei kannst du auch als eingebettete Resource zum Projekt hinzufügen, da die Initiierungswerte nicht geändert werden sollen.
So kannst du die Liste aus der Datei erstellen:
List<Weapon> myList = null;
Ich habe das komplett über LINQ gelöst, weil es am einfachsten ist, wenn man weis wie es geht.
using (var s = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("WpfApplication161.XMLFile1.xml")))//Namespace + Dateiname
{
myList = XDocument.Parse(s.ReadToEnd())//XML aus Resourcen laden
.Root//Weapons-Knoten
.Elements("Weapon")//Jeder Weapon-Knoten
.Select(x =>
new Weapon()//Für jeden Knoten eine neue Waffe erzeugen
{
name = x.Attribute("Name").Value,//Attribute auslesen
attack = int.Parse(x.Attribute("Attack").Value),
speed = int.Parse(x.Attribute("Speed").Value),
image = new BitmapImage(new Uri(x.Attribute("Image").Value, UriKind.RelativeOrAbsolute)),
}).ToList();//Eine List<T> aus der Auflistung machen
}
PS: Ich habe in meinem Beispiel die Bilder Image1.png bis Images3.png in dem Ordner Images im Projekt abgelegt. Bei allen Bildern war der Buildvorgang auf "Eingebettete Resource" gestellt, sodass alles direkt in die Anwendung einkompiliert wird.
Tom Lambert - C# MVP
Bitte bewertet- und markiert Beiträge als Antwort. Danke.
Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter
Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets- Bearbeitet Tom Lambert (Koopakiller)Moderator Sonntag, 15. Juni 2014 13:09 PS
- Als Antwort markiert Bashesz Dienstag, 17. Juni 2014 00:21
Alle Antworten
-
Hi Markus,
du könntest die Skins in deiner Anwendung in eine Resource Datei packen und über die
Eigenschaft "Buildvorgang" als Eingebettete Resource kennzeichnen.
Resourceneinstellungen:
1. Dem Projekt eine neue Resourcendatei hinzufügen "Images.resx"
2. Doppelklick auf die Resourcedatei und bei Resource hinzufügen "Bilder" auswählen
3. Deine Bilder einfügen z.B. Skin1.png & Skin2.png
4. Im neuen Projektordner Resourcen die beiden Bilder durch rechte Maustaste "Eigenschaften"
bei Buildvorgang auf Eingebettete Resource setzen.
Jetzt kannst du in deinem Code auf die Bilder innerhalb der Resourcendatei verweißen
ohne dass diese durch die User bearbeitete werden können, da Sie jetzt Bestandteil
deiner Assembly sind.
Code:
Xaml:
<Window x:Class="ImageAsEmbeddedResource.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> <Image x:Name="imgSkin" Grid.Column="0" Margin="5" /> <StackPanel Orientation="Vertical" Margin="5" Grid.Column="1"> <Button x:Name="btnSkin1" Click="btnSkin_Click" Margin="5" Content="Skin 1" /> <Button x:Name="btnSkin2" Click="btnSkin_Click" Margin="5" Content="Skin 2" /> </StackPanel> </Grid> </Window>
C#
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void btnSkin_Click(object sender, RoutedEventArgs e) { Button button = e.OriginalSource as Button; if (button == null) return; switch (button.Name) { case "btnSkin1": imgSkin.Source = ConvertBitmapToImageSource(Images.Skin1); break; case "btnSkin2": imgSkin.Source = ConvertBitmapToImageSource(Images.Skin2); break; default: throw new InvalidOperationException("Für diesen Button gibt es noch keine Aktion ..."); } } private ImageSource ConvertBitmapToImageSource(System.Drawing.Bitmap bitmap) { if (bitmap == null) throw new ArgumentNullException("bitmap"); // Quelle: http://stackoverflow.com/questions/94456/load-a-wpf-bitmapimage-from-a-system-drawing-bitmap using (MemoryStream ms = new MemoryStream()) { bitmap.Save(ms, ImageFormat.Bmp); ms.Position = 0; BitmapImage bitmapImage = new BitmapImage(); bitmapImage.BeginInit(); bitmapImage.StreamSource = ms; bitmapImage.CacheOption = BitmapCacheOption.OnLoad; bitmapImage.EndInit(); return bitmapImage; } } }
Screenshots:
Gruß
JohSu
- Bearbeitet JohSu Samstag, 14. Juni 2014 23:26
-
Hallo,
erstmal danke für die hilfreiche Antwort.
Besteht hierbei auch die Möglichkeit, das ich in meiner Klasse bei
source = path + "//Sword1.png"
dem Pfad in der Ressource eingebe?
also zB
source = myproject.Properties.Resources.Sword1
Und mit dem Pfad eben direkt per zB Buttondruck das Bild ändere?
Mit freundlichen Grüßen
Markus Ö.
-
Hallo,
Ich habe mir einige Thema dazu durchgelesen. Ich wüsste den Ansatz jedoch brauche ich hierzu noch kurz Hilfe.
Mit folgenden Code kann ich ein Bild aus einer Ressource laden:
Bitmap bmp = new Bitmap(System.Reflection.Assembly.GetEntryAssembly().GetManifestResourceStream("ImageRessource..Resources.Image1.png"));
Wenn ich nun Grid1 dieses Bild zuweißen möchte wie müssten dies aussehen? Da grid1.Background = bmp nicht funktioniert. (Kann nicht von Drawing.Bitmap in MediaBrush konvertiert werden)
Mit freundlichen Grüßen
-
Hi Bashesz,
du kannst die Background Eigenschaft des Grids, unter zuhilfenahme der Helpermethode ConvertBitmapToImageSource aus meinem ersten Beispiel wie folgt setzen:
grid.Background = new ImageBrush(ConvertBitmapToImageSource(Images.Skin1));
Allerdings musst du die Resourcen nicht extra aus der Assembly laden (es sei denn du willst das bewusst so). Es reicht, wenn du wie oben beschrieben eine neue Resourcen Datei anlegest und die Bilder dann dort einfügst.
Wenn deine Resource Datei z.B. Images.resx heißt und dein Bild den Name Skin1.png hat, kannst du in deinem Code direct durch den Aufruf von Images.Skin1 auf das Bild zugreifen.
Gruß
JohSu
-
Hallo,
Danke, Das ganze funktioniert so weit so gut. Jedoch ist der Background des Images irgendwie. Das Bild ist natürlich in .png und transparenter Background, jedoch entsteht ein schwarzer Background im grauen streifen darin obwohl es eigentlich transparent sein sollte.
Mit freundlichen Grüßen
Markus Ö.
- Bearbeitet Bashesz Sonntag, 15. Juni 2014 02:10
-
Hallo zusammen,
warum sich das laden eines Bildes in WPF so schwer machen?image.Source = new BitmapImage(new Uri(@"/myimg.png", UriKind.Relative));
Das erzeugte BitmapImage kannst du überall in WPF einbringen, wo ein Bild benötigt wird. Ein Problem mit Transparenz gibt es da eigentlich nicht. Wenn doch, poste bitte einen Screenshot davon.
Auch auf eine RESX-Datei würde ich versuchen unter WPF zu verzichten, die bringt dir eigentlich keine Vorteile.
Wie viele Bilder hat denn jede Waffe? Wenn jede Waffe nur ein Bild hat, kannst du einfach eine ImageSource-Eigenschaft in der Weapons-Klasse erstellen und diese beim initialisieren zuweisen. Wenn es ein 3D-Modell o.ä. gibt, kannst du auch eine eigene Klasse anlegen, die sämtliche Bilder enthält und eine Instanz dieser Klasse in Weapons einfügen.
An deiner Stelle würde ich eine XML-Datei o.ä. verwenden um alle Waffen mit ihren Initialisierungswerten abzuspeichern. Darin kannst du auch den Namen des Bildes abspeichern. Beim starten des Spiels kannst du nun die Datei auslesen und dynamisch jede Waffe erstellen und zu deiner Liste hinzufügen.
<?xml version="1.0" encoding="utf-8" ?> <Weapons> <Weapon Id="0" Name="Waffe 1" Attack="1" Speed="10" Image="/Images/Image1.png"></Weapon> <Weapon Id="1" Name="Waffe 2" Attack="2" Speed="15" Image="/Images/Image2.png"></Weapon> <Weapon Id="2" Name="Waffe 3" Attack="5" Speed="20" Image="/Images/Image3.png"></Weapon> </Weapons>
Diese Datei kannst du auch als eingebettete Resource zum Projekt hinzufügen, da die Initiierungswerte nicht geändert werden sollen.
So kannst du die Liste aus der Datei erstellen:
List<Weapon> myList = null;
Ich habe das komplett über LINQ gelöst, weil es am einfachsten ist, wenn man weis wie es geht.
using (var s = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("WpfApplication161.XMLFile1.xml")))//Namespace + Dateiname
{
myList = XDocument.Parse(s.ReadToEnd())//XML aus Resourcen laden
.Root//Weapons-Knoten
.Elements("Weapon")//Jeder Weapon-Knoten
.Select(x =>
new Weapon()//Für jeden Knoten eine neue Waffe erzeugen
{
name = x.Attribute("Name").Value,//Attribute auslesen
attack = int.Parse(x.Attribute("Attack").Value),
speed = int.Parse(x.Attribute("Speed").Value),
image = new BitmapImage(new Uri(x.Attribute("Image").Value, UriKind.RelativeOrAbsolute)),
}).ToList();//Eine List<T> aus der Auflistung machen
}
PS: Ich habe in meinem Beispiel die Bilder Image1.png bis Images3.png in dem Ordner Images im Projekt abgelegt. Bei allen Bildern war der Buildvorgang auf "Eingebettete Resource" gestellt, sodass alles direkt in die Anwendung einkompiliert wird.
Tom Lambert - C# MVP
Bitte bewertet- und markiert Beiträge als Antwort. Danke.
Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter
Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets- Bearbeitet Tom Lambert (Koopakiller)Moderator Sonntag, 15. Juni 2014 13:09 PS
- Als Antwort markiert Bashesz Dienstag, 17. Juni 2014 00:21
-
Hallo,
Danke, werde ich mir gleich ansehen. Wie das ganze geschrieben wird ist mir eigentlich egal, hauptsache die User haben keinen Zugriff auf die Bilder, obwohl sie vorhanden sind. Da ich aus Dummheit des Menschen keine Fehler haben möchte.
Mich würde aber interessieren warum eine XML Datei besser wäre als die Klasse? In der Klasse habe ich ebenfalls den Source abgespeichert und lese die Werte beim start aus.
Bei weiteren Problemen werde ich mich hier wenden.
EDIT: Und ja jedes Item hat nur 1 Bild.
Mit freundlichen Grüßen
Markus Ö.
- Bearbeitet Bashesz Sonntag, 15. Juni 2014 17:28
-
Mich würde aber interessieren warum eine XML Datei besser wäre als die Klasse? In der Klasse habe ich ebenfalls den Source abgespeichert und lese die Werte beim start aus.
Hallo,
das ist Geschmackssache. Die meisten lagern gerne ähnliche Datei aus. Auf diese Weise hast du eine Datei, in der alle Daten enthalten sind. Wenn du nun etwas korrigieren willst, musst du nur die XML-Datei anpassen und nicht erst lange im Code suchen. Auch lassen sich solche Dateien leichter übersetzen.
Der benötigte Code ist nun auch eher kurz, sodass es IMHO nur Vorteile bringt.Tom Lambert - C# MVP
Bitte bewertet- und markiert Beiträge als Antwort. Danke.
Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter
Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets