Probleme beim {Binding} von FileOpenPicker an ein GridView

  • Modern UI

Es gibt 18 Antworten in diesem Thema. Der letzte Beitrag () ist von MA-Maddin.

    Probleme beim {Binding} von FileOpenPicker an ein GridView

    Hallo Leute,

    nach dreitägigem Testen, Googlen und noch mehr testen komme ich nicht mehr weiter...

    Ich möchte ein GridView mit den Daten (Bilder) aus einem multiple FileOpenPicker füllen. Die Namen, Pfade etc. der ausgewählten Dateien kann ich bereits erfolgreich als Item in das GridView einfügen. Auf das Bild selbst wird aber anders zugegriffen und ich schaffe es nicht, es ebenfalls an das GridView.Item zu binden, wie es mit den anderen Informationen geht...
    Ich habe erst vor kurzem mit diesen Metro-/WindowsstoreApps angefangen, daher ist es nicht so leicht zu erklären..... Hier mal der dazugehörige Code:

    Click-Event/FileOpenPicker:

    VB.NET-Quellcode

    1. Private Async Sub Button1_Click(sender As Object, e As RoutedEventArgs) Handles Button1.Click
    2. If Not (ApplicationView.Value = ApplicationViewState.Snapped) Or ApplicationView.TryUnsnap Then
    3. Dim openPicker As New FileOpenPicker
    4. openPicker.ViewMode = PickerViewMode.List
    5. openPicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary
    6. openPicker.FileTypeFilter.Add(".jpg")
    7. openPicker.FileTypeFilter.Add(".jpeg")
    8. openPicker.FileTypeFilter.Add(".png")
    9. Dim files As IReadOnlyList(Of StorageFile) = Await openPicker.PickMultipleFilesAsync
    10. If files.Count > 0 Then
    11. Dim output As New StringBuilder("Picked files:" & vbCrLf)
    12. ' Application now has read/write access to the picked file(s)
    13. For Each file In files
    14. output.Append(file.Name & vbCrLf)
    15. Dim fileStream = Await file.OpenAsync(Windows.Storage.FileAccessMode.Read)
    16. Dim Image = New Windows.UI.Xaml.Media.Imaging.BitmapImage()
    17. Image.SetSource(fileStream)
    18. ''' Hier müsste das Image-Element zu file hinzugefügt werden... oder anders
    19. ''' file ist als DataContext an das GridView gebunden ( ItemsSource="{Binding file}" / siehe unten )
    20. ImageGridView.Items.Add(file)
    21. Next
    22. OutputTextBlock.Text = output.ToString
    23. Else
    24. OutputTextBlock.Text = "Operation cancelled."
    25. End If
    26. End If
    27. End Sub


    Hier der XAML-Teil:

    XML-Quellcode

    1. <!-- Template für ein GridView-Item -->
    2. <DataTemplate x:Key="DataTemplate1">
    3. <Grid HorizontalAlignment="Left" Width="250" Height="250">
    4. <Border>
    5. <Image Source="{Binding Image}" Stretch="UniformToFill" AutomationProperties.Name="{Binding DisplayName}"/>
    6. </Border>
    7. <StackPanel VerticalAlignment="Bottom">
    8. <TextBlock Text="{Binding Name}" Height="60" Margin="15,0,15,0"/>
    9. <TextBlock Text="{Binding Path}" Margin="15,0,15,10"/>
    10. </StackPanel>
    11. </Grid>
    12. </DataTemplate>
    13. ...........
    14. <!-- Das GridView: -->
    15. <GridView x:Name="ImageGridView" ItemsSource="{Binding file}" ItemTemplate="{StaticResource DataTemplate1}" SelectionMode="None"/>


    Ich habe schon sämtlichen Beispiel-Code von der MSDN Seite nach Lösungen durchsucht, aber nichts gefunden. Aus dem "Beginner-Tutorial" bzgl. der Ressourcenanbindung an GridViews lässt es sich leider auch nicht schlau machen... dort werden so viele ineinander verschachtelte Klassen verwendet, dass ich da nicht mehr durchsteige :/

    Vielleicht kann mir ja einer von euch weiterhelfen?!
    Vielen Dank schonmal :)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „MA-Maddin“ ()

    Wenn du schon Bindings verwendest, dann ist diese Zeile absolutes Tabu: ImageGridView.Items.Add(file). Erstelle eine Eigenschaft vom Typ ObservableCollection<T>(T steht dabei den Typ von "file in deiner Methode). Anschließend musste die ItemsSource an diese Eigenschaft binden. Wenn du das hast müsste es funktionieren und das DataTemplate übernimmt die Darstellung. Ich hab dir mal schnell nen Beispiel geschrieben wie es funktionieren müsste(in C# -> konvertiers bitte selber):

    C-Quellcode

    1. <GridView x:Name="ImageGridView" ItemsSource="{Binding file}" ItemTemplate="{StaticResource DataTemplate1}" SelectionMode="None"/>
    2. public class MainWindow : Window
    3. {
    4. private ObservableCollection<Bild> _bilder;
    5. public ObservableCollection<Bild> Bilder
    6. {
    7. get { return _bilder ?? (_bilder = new ObservableCollection<Bild>); }
    8. set { _bilder = value; }
    9. }
    10. private void Button1_Click(object sender, RoutedEventArgs e)
    11. {
    12. /*
    13. * Hier ist der Ganze Code... von Button1_Click
    14. * ...
    15. */
    16. //anstatt ImageGridView.Items.Add(file)
    17. Bilder.Add(file);
    18. }
    19. }


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    Danke für die Antwort :)

    Der Code sieht in VB nun so aus:

    VB.NET-Quellcode

    1. Private _bilder() As ObservableCollection(Of T)
    2. Public Property BilderData() As ObservableCollection(Of T)
    3. Get
    4. Return Me._bilder
    5. End Get
    6. Set(value As ObservableCollection(Of T))
    7. Me._bilder = value
    8. End Set
    9. End Property


    Da ich erst wenig mit Klassen und Eigenschaften zu tun hatte, würde ich mich freuen, wenn du mir nochmal erklären könntest, wie ich nun die Dateiinformationen und das Bild in die Eigenschaft bzw. die Collection bekomme?!
    "T steht für den Typ der Elemente in der Auflistung"... Sprich, der Typ von "files"? :huh:

    Ich hab in der For-Each-Schleife des FilePickers ja sozusagen einmal "file" und einmal das Bild. Beides soll der Liste/ItemsSource angefügt werden...

    Sry, bin da gerade etwas dusselig... :S
    Genau. T steht für den Typ deiner Auflistung die du haben möchtest. In deinem Fall StorageFile?
    Außerdem hat der Converter wohl einen Fehler gemacht:

    VB.NET-Quellcode

    1. Private _bilder() As ObservableCollection(Of StorageFile)
    2. Public Property BilderData() As ObservableCollection(Of StorageFile)
    3. Get
    4. If _bilder = Nothing Then
    5. _bilder = new ObservableCollection(Of StorageFile)()
    6. End If
    7. Return Me._bilder
    8. End Get
    9. Set(value As ObservableCollection(Of StorageFile))
    10. Me._bilder = value
    11. End Set
    12. End Property


    Also nochmal


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    Hatte das selbst umgeschrieben... :whistling:

    Ich erhalte jetzt für Zeile 5, 7 und 10 diese Fehlermeldung:
    Der Wert vom Typ "1-dimensionales Array von System.Collections.ObjectModel.ObservableCollection(Of Windows.Storage.StorageFile)" kann nicht in "System.Collections.ObjectModel.ObservableCollection(Of Windows.Storage.StorageFile)" konvertiert werden.

    Und für Zeile 4 das gleiche, dass der "="-Operator für den Typ (System.Collections.ObjectModel.ObservableCollection(Of Windows.Storage.StorageFile)) nicht definiert ist... :wacko:


    Der C# Code funktioniert... da gibt es keine Meldung.
    Da bekomme ich nur irgendwie die XAML-Bindung noch nicht so richtig hin.... :S


    Achso... und ich weiß immernoch nicht (bzw. habs nicht verstanden), wie ich das Bild dazu bekomme? Also das wird ja extra aus dem filestream erstellt.

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „MA-Maddin“ ()

    In Zeile 5 steht: openPicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary und da tritt der Fehler sich nicht auf.


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    Ich meine die Zeilen vom letzten Codeschnipsel ;)
    Also

    VB.NET-Quellcode

    1. Private _bilder() As ObservableCollection(Of StorageFile)
    2. Public Property BilderData() As ObservableCollection(Of StorageFile)
    3. Get
    4. If _bilder = Nothing Then ' hier
    5. _bilder = new ObservableCollection(Of StorageFile)() ' hier
    6. End If
    7. Return Me._bilder ' hier
    8. End Get
    9. Set(value As ObservableCollection(Of StorageFile))
    10. Me._bilder = value ' und hier
    11. End Set
    12. End Property
    Das ist mein Fehler. Ich schreibe das hier alles nur aufm Handy und programmiere seit vielen Jahren kein VB mehr. Mein C# Code(auch vom handy) müsste jedoch funktionieren. Also müsstest du halt den Code selber in einen Converter kopieren. In dem Fall habe ich das diesmal für dich übernommen:

    VB.NET-Quellcode

    1. Private _bilder As ObservableCollection(Of StorageFile)
    2. Public Property Bilder() As ObservableCollection(Of StorageFile)
    3. Get
    4. If _bilder Is Nothing Then
    5. _bilder = New ObservableCollection(Of StorageFile)()
    6. End If
    7. Return _bilder
    8. End Get
    9. Set
    10. _bilder = value
    11. End Set
    12. End Property


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    Okay, vielen Dank dafür! Der Code scheint nun zu laufen.

    Aber kannst du mir bei der 2. Frage bzgl. des Bildes auch noch behilflich sein?

    In dem GridView soll ja neben dem Bild noch Name und Pfad ankommen.
    Bis jetzt sehe ich nur die Möglichkeit, entweder das Bild (Image) oder die komplette Datei (file) an die Eigenschaft zu senden. Bei letzterem müsste ich das Image in einem späteren Schritt erstellen... Innerhalb der Eigenschaft kann ich dies ja nicht tun, weil ich Async icht verwenden kann...
    Du hast ein Template. In das Template kannst du reinpacken was du willst.
    Du kannst ein Image neben den Dateinamen setzen. Verwend einfach das Template das du schon hast oder was ist genau dein Problem?


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    Sry, dass ich das ganze noch nicht komplett durchschaut habe. Ich versuch nochmal mein Problem zu erklären:

    Das XAML-Item-Template soll 3 Dinge ausgeben: Name, Pfad und das Bild anzeigen.

    In dem Click-Ereignis erhalte ich die Dateiinformation via des StorageFile "file".
    Wenn ich nun "file" an das Gridview binde, stehen in dem Template nur Name und Pfad, da file kein Bild ausliefert.
    Dieses wird extra erstellt ( Dim Image = New Windows.UI.Xaml.Media.Imaging.BitmapImage() ... usw).
    Jetzt war mein ursprüngliches Problem, wie ich das Image ebenfalls zum Item-Template liefern kann. Ich kann ja schließlich nur eine Quelle an das Gridview binden.... Also brauche ich eine Datenliste, die Name, Pfad und Bild beinhaltet, so dass ich diese an das GeidView anbinden, und das Template alle 3 Sachen erhält und anzeigen kann.

    Verstehst du? :)
    (MetroApp ~ WPF)

    Korrekt, die Bilder sollen im GridView angezeigt werden.... notfalls nur deren Thumbnails (falls das ein Unterschied macht).

    Ich schau mir mal den Code aus deinem Link an, scheint ja eine ähnliche Situation zu sein. Vielleicht finde ich ja dort Lösungen ;)

    Danke schonmal!
    also wenn pro StorageFile das Bildle mit ins DG muß, dann musstedir eine ViewModel-Klasse schreiben, die das StorageFile wrappert, und zusätzlich ein Image bereitstellt.
    kann man ein DG ja problemlos dran anbinden.

    VB.NET-Quellcode

    1. public Class FileImage
    2. Public Property File As StorageFile
    3. Public Property Image As BitmapImage '(BitmapImage nähme man in Wpf)
    4. end Class


    oder einen IValueConverter schreiben und zum Binding der Image-Spalte mitgeben, der ein StorageFile in ein Image konvertiert.
    Ist aber eiglich komplizierter als das mit dem Wrapper.
    Ich glaube, ich habs jetzt geschnallt :P

    Sieht also nun wie folgt aus:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Async Sub Button1_Click(sender As Object, e As RoutedEventArgs) Handles Button1.Click
    2. If Not (ApplicationView.Value = ApplicationViewState.Snapped) Or ApplicationView.TryUnsnap Then
    3. Dim openPicker As New FileOpenPicker
    4. openPicker.ViewMode = PickerViewMode.List
    5. openPicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary
    6. openPicker.FileTypeFilter.Add(".jpg")
    7. openPicker.FileTypeFilter.Add(".jpeg")
    8. openPicker.FileTypeFilter.Add(".png")
    9. Dim files As IReadOnlyList(Of StorageFile) = Await openPicker.PickMultipleFilesAsync
    10. If files.Count > 0 Then
    11. Dim output As New StringBuilder("Picked files:" & vbCrLf)
    12. ' Application now has read/write access to the picked file(s)
    13. For Each file In files
    14. output.Append(file.Name & vbCrLf)
    15. Dim fileStream = Await file.OpenAsync(Windows.Storage.FileAccessMode.Read)
    16. Dim Image = New Windows.UI.Xaml.Media.Imaging.BitmapImage()
    17. Image.SetSource(fileStream)
    18. Dim neuesBild As New BildKlasse()
    19. neuesBild.Name = file.DisplayName
    20. neuesBild.Pfad = file.Path
    21. neuesBild.Image = Image
    22. ' ImageGridView.Items.Add(neuesBild) ' Das hat einwandfrei funktioniert
    23. Bilder.Add(neuesBild)
    24. Next
    25. OutputTextBlock.Text = output.ToString
    26. Else
    27. OutputTextBlock.Text = "Operation cancelled."
    28. End If
    29. End If
    30. End Sub
    31. Public Class BildKlasse
    32. Public Property Name As String
    33. Public Property Pfad As String
    34. Public Property Image As BitmapImage
    35. End Class
    36. Private _bilder As ObservableCollection(Of BildKlasse)
    37. Public Property Bilder() As ObservableCollection(Of BildKlasse)
    38. Get
    39. If _bilder Is Nothing Then
    40. _bilder = New ObservableCollection(Of BildKlasse)()
    41. End If
    42. Return _bilder
    43. End Get
    44. Set(value As ObservableCollection(Of BildKlasse))
    45. _bilder = value
    46. End Set
    47. End Property

    Ich hab jetzt nur noch nicht die Bindung von der Eigenschaft an das GridView hinbekommen :S
    Wo muss ich denn die Eigenschaft als Resource definieren?
    Irgendwas fehlt mir da noch, denn
    <GridView ItemsSource="{Binding Bilder}"/>
    reicht ja nicht ?(

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „MA-Maddin“ ()

    Habs jetzt nur so hinbekommen:

    VB.NET-Quellcode

    1. ....
    2. Bilder.Add(neuesBild)
    3. Next
    4. ImageGridView.DataContext = Bilder
    5. OutputTextBlock.Text = output.ToString
    6. ....

    XML-Quellcode

    1. <GridView x:Name="ImageGridView" ItemsSource="{Binding}"/>


    Also alles abgehakt.
    Danke an alle Helfer! :)
    wassich noch sehr empfehlen täte: Binding-Picking im Xaml-Editor

    Weil wenn man MVVM für sich nutzt, und die DataContexte geschickt setzt, dann kann man das dort beschriebene BindingPicking betreiben, ohne welches Xaml-Bindings ja eiglich hanebüchen unsicher ist.

    MVVM–Pattern (Josh Smiths Artikel) kennste?


    Weil

    MA-Maddin schrieb:

    VB.NET-Quellcode

    1. ImageGridView.DataContext = Bilder
    sieht eiglich so aus wie voll an MVVM vorbei.