Laden...

-> Listbox mit Bilder Anlage via Codebehind ??

Erstellt von cybermailer vor 10 Jahren Letzter Beitrag vor 10 Jahren 5.285 Views
C
cybermailer Themenstarter:in
14 Beiträge seit 2013
vor 10 Jahren
-> Listbox mit Bilder Anlage via Codebehind ??

Hallo,

ich lerne gerade und komme jetzt bei einer Aufgabe nicht weiter.

Aufgabe:
Erstelle eine Listbox und ein Label in WPF.

Die Listbox soll Bilder enthalten wenn man auf das Bild klickt wird der Name des
Bildes im Label angezeigt.

Die Liste muss via Codebehind erstellt werden.

-> Habt Ihr Tipps, Tutorials, Codeschnipsel bei der Hand?

Was habe ich bis jetzt gemacht?
-> Via xaml eine listbox reingezogen + label

<StackPanel>
        <ListBox Height="182" HorizontalAlignment="Left" Name="meinelistbox" VerticalAlignment="Top" Width="503" SelectionChanged="listBox1_SelectionChanged" />
        <Label Content="Label 1" Height="44" HorizontalAlignment="Left" Name="lblgif" VerticalAlignment="Top" Width="503" />
        <Label Content="Label 2" Height="44" HorizontalAlignment="Left" Name="lbl" VerticalAlignment="Top" Width="503" />
    </StackPanel>

-> Via Codebehind versucht die Bilder aus Ordner einzulesen.

string[] mda = Directory.GetFiles("E:\\Hund"); 
            
            ListBox meinelistbox = new ListBox(); 
            meinelistbox.SelectionMode = SelectionMode.Single;
            meinelistbox.SelectionChanged += listBox1_SelectionChanged;

... Danke für Eure Hilfe

1.552 Beiträge seit 2010
vor 10 Jahren

Hallo cybermailer,

das Stichwort welches du suchst nennt sich ItemTemplate, und SelectedItem.

Gruß,
Michael

Mein Blog
Meine WPF-Druckbibliothek: auf Wordpress, myCSharp

C
cybermailer Themenstarter:in
14 Beiträge seit 2013
vor 10 Jahren

ok das habe ich mir gerade mal angesehen - muss dazu noch googlen um zu sehen was die Dinger machen - soweit sind wir im Stoff noch nicht...

Meine Probleme
a) Wie lese ich Bilder aus einem Ordner ein und zeige die in einer
Liste schön gleichmäßig an (obwohl verschiedene Größen)
Den Namen dazu kann ich wahrscheinlich ohnehin via Index nr hardcodieren...
b) Bilder in List schön formatiert untereinander aus geben
als Liste
c) Bei Klick auf Bild Bildernamen ausgeben

Vielleicht kann man ja auf die einzelnen Bereiche Tipps geben...DANKE!

ps. hoffe ich denke nicht zu kompliziert is ja schon spät...

1.552 Beiträge seit 2010
vor 10 Jahren

a) BitmapImage
b) ItemTemplate
c) SelectedItem

Wir helfen gerne bei Hausaufgaben und geben Tipps, jedoch sollte auch etwas Eigeninitiative da sein.

Mein Blog
Meine WPF-Druckbibliothek: auf Wordpress, myCSharp

C
cybermailer Themenstarter:in
14 Beiträge seit 2013
vor 10 Jahren

Danke!

Mit a) BitmapImage kann ich was anfangen da kann ich ansetzen.

Punkt b) und c) sind mir derzeit noch nicht bekannt da muss ich mich noch einlesen.

Meinst du wäre das dann die einfachste Lösung?

Habe dieses Tutorial gefunden (durch deinen Tipp) Tutorial

Dann sind schon mal die Bilder eingelesen.

Die Namen erhalte ich dann in der Ausgabe durch deinen Tipp (b & c?)

C
cybermailer Themenstarter:in
14 Beiträge seit 2013
vor 10 Jahren

Ich hab es jetzt soweit, dass die Bilder in einer Listbox angezeigt werden:

Meine XAML:

<Window x:Class="Listbox_Hundv2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Listbox_Hundv2" 
    Title="Custom ItemsPanel" Height="800" Width="300"
    WindowStartupLocation="CenterScreen"
    >
    
    <Window.Resources>
        <Style TargetType="{x:Type ListBox}">

            <!-- BOF Formattierung der Daten -->

            <Setter Property="ItemTemplate">
                <Setter.Value>
                    <DataTemplate>
                         <Image Source="{Binding Path=UriSource}" Stretch="Fill" Width="120" Height="120" />
                    </DataTemplate>
                </Setter.Value>
            </Setter>

            <!-- EOF Formattierung -->

            <!-- Horizontal deaktiviert -->
            <Setter 
        Property="ScrollViewer.HorizontalScrollBarVisibility" 
        Value="Disabled" 
        />

        </Style>
    </Window.Resources>

    <Window.DataContext>
        <ObjectDataProvider ObjectType="{x:Type local:Hundloader}" MethodName="LoadImages" />
        
    </Window.DataContext>

    <!-- Content hinzufügen -->
    <ListBox ItemsSource="{Binding}" />

</Window>

Meine CS Datei:

using System;
using System.Collections.Generic;
using System.IO;
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.Shapes;

namespace Listbox_Hundv2
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }

    public static class Hundloader
    {
        public static List<BitmapImage> LoadImages()
        {
            List<BitmapImage> hundImages = new List<BitmapImage>();

            DirectoryInfo hundordner = new DirectoryInfo(@"..\..\Hund");


            foreach (FileInfo hundbilder in hundordner.GetFiles("*.jpg"))
            {
                Uri uri = new Uri(hundbilder.FullName);
                hundImages.Add(new BitmapImage(uri));
            }

            return hundImages;
        }
    }
}

Jetzt habe ich ein Problem bei dem ich nicht durchchecke wie kann ich nun bei klick auf gewisses Bild einen Namen anzeigen lassen? (Der von mir definiert wird)

Danke für Eure Hilfe.

1.552 Beiträge seit 2010
vor 10 Jahren

Du hast ein z.B. Label wessen Content du mit dem SelectedItem der Liste bindest.


<Label Content="{Binding Path=SelectedItem, ElementName=myListBox}">

oder du Bindest an die Code-Behind Datei:


<ListBox .... SelectedItem="{Binding Path=SelectedPicture}"/>
<Label Content="{Binding Path=SelectedPicture}"/>

Um jedoch den Bildnamen anzuzeigen, müsstest für die du die Liste, welche du an die ListBox bindest, eine Klasse erstellen welche dir den Namen und die URI beinhaltet.

Mein Blog
Meine WPF-Druckbibliothek: auf Wordpress, myCSharp

5.299 Beiträge seit 2008
vor 10 Jahren

BitmapImage stellt doch bereits eine Property SourceUri bereit - kann man da nicht dran binden?

Der frühe Apfel fängt den Wurm.

C
cybermailer Themenstarter:in
14 Beiträge seit 2013
vor 10 Jahren
so stehe und nun an...

Schaffe das finish nicht ganz der Darstellung

-> Es soll eine Listbox mit Bildern geben je nachdem welches Bild
genannt wurde wird die Rasse angezeigt.

Meine XAML:
*hier wird mir ein Fehler ausgegeben das die local:Hund Typ
nicht gefunden wurde

<Window x:Class="Listbox_Hundv3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:Listbox_Hundv3"
        Title="MainWindow" Height="350" Width="525">

    <ListBox x:Name="lstBox">
        <ListBox.ItemTemplate>
            <DataTemplate DataType="{x:Type local:Hund}">
                <StackPanel>
                    
                    <Image Source="{Binding Pfad}" />
                    <TextBlock Margin="3" Text="{Binding Rasse}"/>
                    
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Window>

Meine CS Datei:

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;

namespace Listbox_Hundv3
{
    /// <summary>
    /// Interaktionslogik für MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window

    {
        List<Hund> hunderassenliste;

        public MainWindow()
        {
            hunderassenliste = new List<Hund>();
            hunderassenliste.Add(new Hund() { Rasse = "Dogge" , Pfad ="C:/Users/Acer/Downloads/CustomItemsPanel/CustomItemsPanel/Listbox_Hundv3/Hund/dogge.jpg"});
            hunderassenliste.Add(new Hund() { Rasse = "Puddel", Pfad = "C:/Users/Acer/Downloads/CustomItemsPanel/CustomItemsPanel/Listbox_Hundv3/Hund/puddel.jpg" });

            InitializeComponent();

            /*Damit alle darauf zugreifen können nicht nur Listbox*/
            this.DataContext = hunderassenliste;
        }

        /*Objekt Hund erzeugen*/

        public class Hund
        {
            private string rasse;
            private string pfad;

            public string Rasse
            {
                get { return rasse; }
                set { rasse = value; }
            }

            public string Pfad
            {
                get { return pfad; }
                set { pfad = value; }
            }

            public override string ToString()
            {
                return Rasse + " " + Pfad;
            }
        }

        private void lstimge_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {

        }

        

        

        
    }
}

z.B. das hier schaffe ich - von der Funktion her ok aber ohne Bild:

<Grid>
        <StackPanel Margin="5" Name="stackPanel1"  >
            <ListBox  Name="ListBox" 
                      IsSynchronizedWithCurrentItem="True" Height="186" 
                      ItemsSource="{Binding}"/>
            <TextBox Height="23" Name="textBox1" 
                     Text="{Binding Path=Rasse, UpdateSourceTrigger=PropertyChanged}"/>
        </StackPanel>
    </Grid>

Mit Bild check ich mich nicht durch...

Danke für die Hilfe

5.299 Beiträge seit 2008
vor 10 Jahren

dein Problem ist, dass bei dir die Hund-Klasse eingeschachtelt in die Window1-Klasse ist.

Mach die Klasse Hund in eine eigene Datei - dassis eh wesentlich übersichtlicher.

Auch fände ich gut, wennman die blöden generierten Kommentare nicht dulden würde:


    /// <summary>
    /// Interaktionslogik für MainWindow.xaml
    /// </summary>

weil wer das nicht auch ohne Kommentar wüsste, der sollte sich den Code garnet angugge dürfen.

 /*Objekt Hund erzeugen*/

hingegen ist ein "lügender" Kommentar, die Klasse Hund ist halt die Klasse Hund, da wird kein Hund erzeugt, sondern das ist die Klasse Hund, und das steht da ja bereits als Code, und braucht folglich nicht hinzukommentiert werden.

Aber dassis zweitrangig, wichtig ist, die Einschachtelung der Klasse Hund aufzulösen.

Der frühe Apfel fängt den Wurm.

C
cybermailer Themenstarter:in
14 Beiträge seit 2013
vor 10 Jahren

Ja das habe ich gerade gemacht damit ist der Fehler verschwunden.
(Also Hund in eine eigene Klasse gepackt)

Meine XAML sieht nun so aus:

<ListBox x:Name="lstBox" ItemsSource="{Binding}">
        <ListBox.ItemTemplate>
            <DataTemplate DataType="{x:Type local:Hund}">
                <StackPanel>
                    <TextBlock Margin="3" Text="{Binding Rasse}"/>
                    <Image Source="{Binding Pfad}"/>
                </StackPanel>
                
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

Jetzt habe ich nur noch das Problem dass ich nicht will dass der Name direkt über dem Bild ist sondern nur aufgerufen wird sobald das Bild geklickt wird z.B. am Ende des Fensters ...

5.299 Beiträge seit 2008
vor 10 Jahren

dazu brauchst du einen zusätzlichen Textblock, der an Listbox.SelectedItem gebunden ist, bzw. an DataContext.CurrentItem.

Im Anhang übrigens meine Lösung (allerdings als Bild-ViewModel wird die BitmapImage-Klasse selbst verwendet).

Beachte, dass durch Setzen des DataContexts im Xaml Binding-Picking im Xaml-Editor ermöglicht wurde.

Der frühe Apfel fängt den Wurm.

C
cybermailer Themenstarter:in
14 Beiträge seit 2013
vor 10 Jahren

Hallo,

diesen Ansatz kenne ich, hab ich mir auch schon angesehen, ist aber mit meinen derzeitigen Wissen (6. Unterrichtsstunde WPF) noch zu hoch für mich...

Habe es jetzt bereits umgekehrt gelöst:

<Grid>
        <StackPanel Margin="5" Name="stackPanel1"  >
            <Image Source="{Binding Pfad}" Stretch="Fill" Width="120" Height="120" />
            <ListBox  Name="ListBox" 
                      IsSynchronizedWithCurrentItem="True" Height="186" 
                      ItemsSource="{Binding}"/>
            <TextBox Height="23" Name="textBox1" 
                     Text="{Binding Path=Rasse, UpdateSourceTrigger=PropertyChanged}"/>
        </StackPanel>
    </Grid>

Nur andersrum so wie ich es benötige haut das nicht hin.

Ich brauch es dass die Bilder i.d. Listbox sind und der Namen angezeigt wird.

Anbei das Projekt - Wäre super wenn du helfen könntest...

C
cybermailer Themenstarter:in
14 Beiträge seit 2013
vor 10 Jahren

Habe es jetzt auf so umgeändert hoffe das ist einigermaßen ok.

Jetzt fehlt nur die automatische Aktualisierung bei anderer Auswahl sonst
steht immer Dogge...

<Grid>
    <ListBox Name="listBox" ItemsSource="{Binding}" Height="258">
        <ListBox.ItemTemplate>
            <DataTemplate>            
                    <StackPanel>
                        <Image Width="100"
                   Height="100"
                   Source="{Binding Pfad}" />                     
                    </StackPanel>  
            </DataTemplate>
        </ListBox.ItemTemplate>
        
    </ListBox>
        <TextBlock Height="23" Name="textBox1" Text="{Binding Path=Rasse}" Margin="220,300,150,20" />
</Grid>

Fast am Ziel ...

C
cybermailer Themenstarter:in
14 Beiträge seit 2013
vor 10 Jahren

Geschafft:

IsSynchronizedWithCurrentItem="true"

Jetzt habe nur 1 Zusatzfrage ich habe ja die Pfadangaben zu den Bildern hardcodiert.

Man kann die ja dynamisch einlesen so wie es auch du gemacht hast.

Aber wie und wo verknüpft man nun das Puddel Bild mit dem Objekt Puddel?

5.299 Beiträge seit 2008
vor 10 Jahren

bin nicht sicher, was du meinst.
Die Image-Klasse kann offensichtlich den String Pfad in eine bildlich darstellbare BitmapSource konvertieren.

Das ist übrigens garnet schön gelöst mit den vollen DateiPfaden.
Günstiger ist, die Dateien als Resource einzubinden, und ihre Uris anzugeben.
Uri ist sowas ähnliches wie ein Dateipfad, nur mit wirklich kranker Syntax. Aber dafür ist ein Uri, der auf eine Resource-Datei verweist, 100% portabel.

Der frühe Apfel fängt den Wurm.

C
cybermailer Themenstarter:in
14 Beiträge seit 2013
vor 10 Jahren

Danke! Ist echt eine große Hilfe um Uris zu verstehen.

Frage:

Wieso hast du neben der Hundklasse noch weitere gemacht?
Wie MainModel (Wann wird diese aufgerufen?) und ViemodelLocator.

Speziell beim diesem check ich jetzt nicht was der genau in diesem
konrekten Bsp. macht.

Danke.

5.299 Beiträge seit 2008
vor 10 Jahren
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace UriBindings {

   public class MainModel {

      public MainModel() {
         var sUri = "pack://application:,,,/UriBindings;component/Hund/";
         var hunderassenliste = new List<Hund>();
         hunderassenliste.Add(new Hund() { Rasse = "Dogge", Uri = new Uri(sUri + "dogge.jpg") });
         hunderassenliste.Add(new Hund() { Rasse = "Pudel", Uri = new Uri(sUri + "puddel.jpg") });
         Hunde = hunderassenliste;
      }
      public List<Hund> Hunde { get; set; }
   }

   public class ViewmodelLocator {
      private static MainModel _MainModel = new MainModel();
      public MainModel MainModel {
         get { return _MainModel; }
      }
   }
   
   public class Hund {
      public string Rasse { get; set; }
      public Uri Uri { get; set; }
   }

}

Ja, dassis umständlich, aber schon bei nur geringer Anwendungskomplexität endet man in diesem oder einem vergleichbaren Pattern.
Also dieses ist der Locator-Pattern: ViewmodelLocator ist eine blöde Klasse mit nur einer Property. Der Witz ist, dass egal wo und wieviele ViewmodelLocator erzeugt werden - die Property "MainModel" gibt immer dasselbe Mainmodel zurück, da sie auf ein static Field zurückgreift.
(Der Locator-Pattern ähnelt also bisserl dem Singleton-Pattern.)

MainModel nenne ich immer das Gesamt-Model einer Anwendung. Alle Viewmodels, bei denen das erforderlich ist (es gibt auch annere) fließen hier zusammen und werden als Property bereitgestellt.
Ist hier nur eine Liste von Hunden.

So, und der ViewmodelLocator wird im Xaml ganz oben aufgehängt, nämlich als Resource in app.xaml:

<Application x:Class="UriBindings.App"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:UriBindings"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
    <local:ViewmodelLocator x:Key="Root"/>
  </Application.Resources>
</Application>

An diesen ViewmodelLocator kann nun jeder View der gesamten Anwendung seinen DataContext anbinden, und er wird immer an genau ein und dasselbe MainModel anbinden:

<Window x:Class="UriBindings.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:UriBindings"
        Title="MainWindow" Height="550" Width="525"
        DataContext="{Binding Source={StaticResource Root}, Path=MainModel}">

Das schöne daran: Kein CodeBehind, und an jeder Stelle im Xaml wird Binding-Picking im Xaml-Editor unterstützt.

Der frühe Apfel fängt den Wurm.

C
cybermailer Themenstarter:in
14 Beiträge seit 2013
vor 10 Jahren

jo, danke! Ist ziemlich komplex für mein Hirn.

Du eine Frage wenn ich mein Projekt, nur auf variable Namen umstellen möchte welche Punkte muss ich dabei beachten damit es klappt habe es nämlich gerade versucht bekomme aber die Bilder nicht angezeigt.

Die Namen klappt perfekt aber eben die Bilder scheinen nimma auf...

Weil so klappts nicht:

<Grid>
        <ListBox Name="listBox" ItemsSource="{Binding}" Height="258" IsSynchronizedWithCurrentItem="true">
        <ListBox.ItemTemplate>
            <DataTemplate>
                    <StackPanel>
                        <Image Width="100" Height="100" Source="{Binding Path=Pfad}" />
                        <TextBlock Text="{Binding Path=Pfad.Segments[3]}" />
                    </StackPanel>
                </DataTemplate>
        </ListBox.ItemTemplate>
        
    </ListBox>
        <TextBlock FontWeight="Bold" Height="23" Name="textBox1" Text="{Binding Path=Rasse}" Margin="220,300,150,20" />
        
</Grid>

public List<Hund> hunderassenliste;

        public MainWindow()
        {
            hunderassenliste = new List<Hund>();

            var sUri = "pack://application:,,,/Listbox_Hundv3;component/Hund/";
            hunderassenliste.Add(new Hund() { Rasse = "Dogge", Pfad = new Uri(sUri + "dogge.jpg") });
            hunderassenliste.Add(new Hund() { Rasse = "Pudel", Pfad = new Uri(sUri + "puddel.jpg") });

            InitializeComponent();

            /*Damit alle darauf zugreifen können nicht nur Listbox*/
            this.DataContext = hunderassenliste;
        }
public class Hund
    {
            private string rasse;
            //private string pfad;

            public string Rasse
            {
                get { return rasse; }
                set { rasse = value; }
            }
        /*
            public string Pfad
            {
                get { return pfad; }
                set { pfad = value; }
            }
        */
            public Uri Pfad 
            { 
                get; 
                set; 
            }
        
    }

Danke.

5.299 Beiträge seit 2008
vor 10 Jahren

keine Ahnung - würdich halt nie so machen, weil das unterstützt das Binding-Picking nicht, und siehste ja, wie schnell dann was nicht klappt.

ah - vlt. hast du deine Dateien nicht als Resource eingebunden.

Der frühe Apfel fängt den Wurm.

C
cybermailer Themenstarter:in
14 Beiträge seit 2013
vor 10 Jahren

Ahh danke so einfach kann die Lösung sein 😉

Ich baue jetzt nämlich Schritt für Schritt in Richtung Deine Lösung damit ich verstehe und lerne was da passiert ...

Danke für Deine Bemühungen!

Für alle dies auch wissen wollen:
Ordner im Projekt anlegen / Rechtsklick auf Ordner / und unter Visual hinzufügen / Vorhandes Element -> Bilder auswählen.
(Im Projektexplorer)

5.299 Beiträge seit 2008
vor 10 Jahren

hier nochma die Doku für gepackte uris. http://msdn.microsoft.com/de-de/library/aa970069.aspx
Beachte den Unterschied von "Paket-URIs der Ressourcendatei" und "Paket-URIs der Inhaltsdatei"

Der frühe Apfel fängt den Wurm.