Dynamische UserControls... (Edit: Binding)

  • Modern UI

Es gibt 34 Antworten in diesem Thema. Der letzte Beitrag () ist von Eistee.

    Dynamische UserControls... (Edit: Binding)

    Hey,

    Hab da ein Problem mit dem Anzeigen von dynamisch erstellten UserControls.

    Das UserControl:
    Spoiler anzeigen

    XML-Quellcode

    1. <UserControl
    2. x:Class="Flip_Layout_Test_02_VB.uc_Directory"
    3. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    4. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    5. xmlns:local="using:Flip_Layout_Test_02_VB"
    6. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    7. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    8. mc:Ignorable="d"
    9. d:DesignHeight="100"
    10. d:DesignWidth="200">
    11. <Grid x:Name="uc_ContentGrid" MinHeight="100" MinWidth="100" Width="200" Height="100" MaxWidth="200" MaxHeight="100" Background="#666666">
    12. <Grid.ColumnDefinitions>
    13. <ColumnDefinition Width="1*" />
    14. <ColumnDefinition Width="2*" />
    15. </Grid.ColumnDefinitions>
    16. <Image Margin="10,10,10,40" Name="_Image" x:FieldModifier="Public" />
    17. <CheckBox Name="_Checkbox" Checked="Checkbox_Checked" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,5" x:FieldModifier="Public" />
    18. <TextBlock Name="_Textbox" Grid.Column="1" Margin="5,10" TextTrimming="None" TextWrapping="Wrap" FontSize="16" Text="" x:FieldModifier="Public" />
    19. </Grid>
    20. </UserControl>


    Control hinzufügen:

    VB.NET-Quellcode

    1. Public Sub Add_uc_Directory(ByVal FolderName As String)
    2. Dim uc_D As uc_Directory
    3. uc_D = New uc_Directory()
    4. uc_D._Textbox.Text = FolderName
    5. uc_D.Width = 200
    6. uc_D.Height = 100
    7. uc_D.Visibility = Windows.UI.Xaml.Visibility.Visible
    8. Me.DirectoryContainer.Children.Add(uc_D)
    9. End Sub


    Me ist eine instanz von Public Class MainPage welche dieses Grid beinhaltet:

    XML-Quellcode

    1. <Grid Grid.Column="1" Grid.Row="1" Name="DirectoryContainer" Width="Auto" Height="Auto" ></Grid>



    Habt ihr eventuell eine Idee was ich vergessen haben könnte?
    oder
    Seht ihr eventuell einen Fehler?


    Was ich sagen kann, Public Sub Add_uc_Directory(ByVal FolderName As String) wird definitiv 7x aufgerufen!

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Eistee“ ()

    du bist noch ganz in WinForms verfangen, was?
    In Wpf added man keine Controls.

    Wenn du viele Controls sehen willst, brauchst du zunächstmal viele Daten.
    Dann machste ein ListenControls ins Xaml, und bindest ItemsSource an die Daten.
    Ein DataTemplate ins ListenControl, und in dem DataTemplate erscheint dein Ucl, und wird an eine Daten-Instanz gebunden.

    gugge 4ViewsWpf - post#2, da issn einfaches DataTemplates für FileInfo gebastelt.
    Die verschachtelten Controls dieses Templates könnten auch als UserControl ausgelagert sein - das tut sich nix.

    ErfinderDesRades schrieb:

    bist noch ganz in WinForms verfangen, was?

    Oh ja, leider.

    ErfinderDesRades schrieb:

    brauchst du zunächstmal viele Daten

    Hab ich:

    VB.NET-Quellcode

    1. For Each StorageFolder In Await _Folder.GetFoldersAsync
    2. If Cancel Then
    3. Return
    4. End If
    5. _Childs.Add(StorageFolder)
    6. Next


    Das Ziel war es, ein WrapGrid mit einem UserControl pro Ordner zu füllen.
    Bin mir nicht sicher ob ich verstanden habe was mit ListenControls gemeint ist, war damit ein ItemsCOntrol gemeint?
    Also sowas hier:

    XML-Quellcode

    1. <ItemsControl Name="Test" ItemsSource="{Binding Path=_Folders}" ScrollViewer.HorizontalScrollBarVisibility="Visible">
    2. <ItemsControl.ItemsPanel>
    3. <ItemsPanelTemplate>
    4. <WrapGrid Orientation="Horizontal" />
    5. </ItemsPanelTemplate>
    6. </ItemsControl.ItemsPanel>
    7. <ItemsControl.ItemTemplate>
    8. <DataTemplate>
    9. <Common:uc_Directory width="200" height="100" />
    10. </DataTemplate>
    11. </ItemsControl.ItemTemplate>
    12. </ItemsControl>


    Wobei "_Folders" dann eine Public _Folders As ObservableCollection(Of StorageFolder) ist.



    Edit:

    ErfinderDesRades schrieb:

    Ich empfehle, konsequent zu versuchen, alle Bindings ausschließlich über das Property-Fenster zu setzen

    Wie erstell ich eigentlich Dependancy Propertys die einem im Eigenschaften Fenster zur Auswahl stehen?
    Die Liste _Folders = New ObservableCollection(Of StorageFolder) sollte ja die Daten liefern.
    Bis jetzt hab ich nur fertige Propertys von z.B. einem TextBlock genommen.




    Bin mit WPF noch total unsicher, aber ich hab leider nur wenig zeit um das Projekt fertig zu stellen :thumbdown:

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „Eistee“ ()

    ErfinderDesRades schrieb:

    Die verschachtelten Controls dieses Templates könnten auch als UserControl ausgelagert sein - das tut sich nix.

    Hatte ich irgendwie überlesen bis ich es gerade selber im XAML Editor gesehen habe, wie genial ist den WPF eigentlich :D
    Aber wofür brauch man dann noch UserControls? Ok zum auslagern falls es mal zu groß/komplex werden sollte bestimmt.

    Bin jetzt auf die - verschachtelten Controls in Templates Methode - umgestiegen da ich schon wieder probleme mit der Namespace-Syntax habe.
    Die Intellisense erkennt! mein Namespace+Usercontrol doch sobald ich enter drücke, bekomme ich den Fehler "Control XY in dem Namespace nicht bekannt".
    Obwohl mir die Intellisense das sogar noch angeboten hatte.

    Also für ein wirklich Idiotensicheren Artikel/Tutorial über das Namespace System wär ich wirklich sehr dankbar.
    Also falls jemand lust hätt :D

    Gruß per Eiswürfel gekühlter Eistee
    Ne daran liegt es nicht (mehr), das war eins der Probleme zuvor.
    Bis ich gemerkt habe das er es eventuell noch nicht kennt, hat es aber auch erstmal gedauert.

    Also falls jemand das hier liest und eine Namespace Erklärung for Dummies kennt, wär ich über einen Link dorthin sehr erfreut ^^
    Kein FrameworkElement.FindResource kein Windows.Data.ObjectDataProvider WinRT ist 'nen Brechmittel :rolleyes:
    Weiß jemand wie man in WinRT eine ObservableCollection bindet ohne sich die Finger zu brechen?

    Versuche gerade die Methode von ErfinderDesRades ich hoffe wenigstens so läuft es...

    Bin zu weit davon abgewichen (da in WinRT das System.IO fehlt, DirectoryInfo, FileInfo) aber es funktioniert fast?(

    XML-Quellcode

    1. <GridView>
    2. <ItemsPanelTemplate>
    3. <WrapGrid Orientation="Horizontal" MaximumRowsOrColumns="3"/>
    4. </ItemsPanelTemplate>
    5. <GridView.ItemTemplate>
    6. <DataTemplate>
    7. <Grid Width="200" Height="100">
    8. <Grid.DataContext>
    9. <custom:Directory_ViewModel/>
    10. </Grid.DataContext>
    11. <Grid.ColumnDefinitions>
    12. <ColumnDefinition Width="1*" />
    13. <ColumnDefinition Width="2*" />
    14. </Grid.ColumnDefinitions>
    15. <Image Name="Bild" Width="20" Height="20" Margin="5,5,10,5" Grid.Column="0" />
    16. <TextBlock Name="Text" VerticalAlignment="Top" HorizontalAlignment="Stretch" Grid.Column="1" Text="{Binding Folders[0].DisplayName, Mode=OneWay}" />
    17. </Grid>
    18. </DataTemplate>
    19. </GridView.ItemTemplate>
    20. </GridView>


    Durch das Text="{Binding Folders[0].DisplayName, Mode=OneWay}" wird nur ein GridView.Item erstellt.
    Es ist das welches man auch im Designer sehen kann.

    Gibt es eine Möglichkeit mit der gleichen Binding Methode an alle Folders zu kommen?
    Sowas wie Binding Folders[*].DisplayName oder so etwas in der Art?

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Eistee“ ()

    zu so Ausschnitten kannman nix sagen, weil der DataContext unbekannt ist.
    Eine Auflistung, wie etwa die Folders bindet man an eine ItemsSource.
    Dann werden auf die FolderItems automatisch die im ItemsControl angelegten DataTemplates angewandt.
    An Folders[0] zu binden ist total exotisch.

    Aber das müsstedoch zum Kuckuck in Binding-Picking im Xaml-Editor klargestellt sein.
    Du bist ein VB Gott! :D

    Mein DataContext:

    XML-Quellcode

    1. <Page.DataContext>
    2. <CUSTOM:Directory_ViewModel/>
    3. </Page.DataContext>


    Obwohl im Grid, im <DataTemplate> habe ich auch nochmal einen DataContext festgelegt.

    XML-Quellcode

    1. <Grid Name="Fake_UC" Width="200" Height="100">
    2. <Grid.DataContext>
    3. <CUSTOM:Directory_ViewModel/>
    4. </Grid.DataContext>


    Das äußerste Grid welches die Controls halten soll (also nicht das ganz außen), wurde jetzt über die ItemSource gebunden:
    <GridView ItemsSource="{Binding Folders}">

    Und siehe da es wird für jeden Ordner das Template Konstrukt erstellt!!
    (Dachte immer dafür wäre das <DataTemplate> gedacht, aber jetzt hab ichs verstanden)
    Vielen vielen dank, habe mir schon 2 Nächte deswegen um die Ohren geschlagen :wacko:

    Werd mich mal weiter an dein Video/Artikel halten und versuchen die einzelnen Propertys an die Controls im Template zu binden.
    Ich hoffe es klappt, ich werde mich melden.

    Vielen dank @ErfinderDesRades: !

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Eistee“ ()

    So ich muss mich leider nochmal melden.

    Edit: Der Expanderinhalt ist ob­so­let
    Spoiler anzeigen
    Ich bekomme es nicht hin, einen <Texblock Text=""> an ein Property einer Klasseninstanz welche sich in einer Liste befindet zu binden.

    Das DataContext der Page:

    XML-Quellcode

    1. <Page.DataContext>
    2. <CUSTOM:Directory_ViewModel/>
    3. </Page.DataContext>


    Directory_ViewModel hält die Liste(Of Folder):

    VB.NET-Quellcode

    1. Public NotInheritable Class Directory_ViewModel
    2. Public Shared Property Folders As New ObservableCollection(Of Folder)
    3. End Class


    Klasse Folder hält den die zwei Propertys Name und Pfad:

    VB.NET-Quellcode

    1. Public Class Folder
    2. Public Shared Property Name As String
    3. Public Shared Property Pfad As String
    4. Private sfolder As StorageFolder
    5. Public Sub New(ByVal StorageFolder As StorageFolder)
    6. sfolder = StorageFolder
    7. Name = sfolder.DisplayName
    8. Pfad = sfolder.Path
    9. End Sub
    10. End Class


    Wenn ich über den Designer für den <Textblock Text""> eine "Datenbindung erstellen..." (Kopf) möchte:


    Und Name wähle, bekomme ich diese Zeile xaml:

    XML-Quellcode

    1. Text="{Binding Folders[0].Name}"


    Nur haben jetzt ALLE Items den Name der 1. Instanz in der Directory_ViewModel.Folders Liste.
    Und einfach die Klammer mit der Index angabe löschen ==> Text="{Binding Folders.Name}"
    funktioniert natürlich nicht.

    Also wenn da jemand eine Idee hätte ?(
    Bin jetzt schon 2-3 Tage dran und finde einfach nicht die Lösung.


    Habe das ganze jetzt wie ich immer hingebkommen, das der Designer als binding nur Folders.Name anbietet.
    Nur hab ich dadurch erkannt, das mit den gefundenen Ordnern irgendwas nicht stimmen muss.
    Den es wird immer der Letzte Ordner im angegebenen Verzeichnis verwendet:


    Falls wer in der Lage ist Die Anonyme asynchrone Funktion von @ErfinderDesRades: zu debuggen könnte man den Fehler eventuell finden.
    Denn ich glaube die List Of Folder ist voll mit ein und dem selben Element, kann es aber nicht beweisen/prüfen :S

    Hier mal das Projekt:
    Flip_Layout_Test_02_VB.zip
    Dateien

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Eistee“ ()

    tja, ich kriegs nicht gebacken, das Teil auf 2010 zu downgraden, und 2012 will sich aus ieinem dunklen Grund nicht funktionsfähig installieren lassen.

    kriege beim Startversuch von 2012 immer IrgendsoneKryptischeDll täte fehlen (name vergessen, und 2012 auch schon zum 3.mal installiert + deinstalliert)
    @ErfinderDesRades: Nabend und danke das Du mir zu helfen versuchst.
    Ich weiß ja nicht welche Windows Version Du installiert hast, aber für dieses Projekt muss es Windows 8 sein.
    Außerdem Visual Studio 2012 Professional oder Ultimate ]oder eben Visual Studio Express für Windows 8 (Die Desktop Version funktioniert nicht).
    Das ist das blöde an dem ganzen WinRT kram, es muss auch zum entwickeln Windows 8 forhanden sein.
    Und das Projekt downgraden würde kein Sinn machen da "WinRT WPF" und "WPF Normal" ja ein großer unterschied ist.
    Was mir wohl auch so viele Probleme bereitet :S
    Hallo erst einmal, ich konnte den Fehler jetzt auf dieses Stück Code eingrenzen

    VB.NET-Quellcode

    1. Class TEST
    2. Public Sub New()
    3. Dim root = KnownFolders.VideosLibrary
    4. Dim loadFolders As Action(Of StorageFolder) = Nothing
    5. loadFolders = _
    6. Async Sub(sf As StorageFolder)
    7. For Each childDir In Await sf.GetFoldersAsync
    8. Directory_ViewModel.Folders.Add(New Folder(childDir))
    9. Next
    10. End Sub
    11. loadFolders(root)
    12. End Sub
    13. End Class


    Denn wenn ich per Hand (WinRT Folder Picker) mehrere Ordner hinzufüge funktioniert alles tadellos.
    Hätte Wer eine Idee warum das Stücken hier nicht das macht was es soll?

    Diese Asynchrone Methode wird verwendet: GetFoldersAsync
    Das ganze hatte aus einer Methode von @ErfinderDesRades: (welche ich gerade nicht mehr finden kann) abgewandelt.

    Bin nicht gerade gut was asynchrone programmierung angeht, bzw. muss ich mir das nochmal durchlesen.
    Hatte das bis jetzt immer nur überflogen, weil bisher brauchte man da ja kaum.


    Also das falsche Ergebnis dieser Methode sieht so aus, anstatt jeden Ordner im angegebenen Ordner aufzulisten, wird Pro Ordner
    im Odner immer der letzte in die Liste aufgenommen und ausgegeben:

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Eistee“ ()

    tja - leider kein 2012, aber kann mir sehr gut vorstellen, dass man so mit Async nicht umspringen darf.
    also den rekursiven Aufruf in den Nebenthread verlagert - also ich kanns nicht ganz durchdenken, welche Auswirkungen, aber es klingeln iwie Alarmglocken. ;)
    vlt. besser die anonyme Methode als ganzes async aufrufen.
    Hab das ganze jetzt mal in einen Button gelegt:

    VB.NET-Quellcode

    1. Private Sub cmd_AUTOLOAD_Click(sender As Object, e As RoutedEventArgs)
    2. TEST.LoadFolders(KnownFolders.PicturesLibrary)
    3. End Sub
    4. Public Class TEST
    5. Public Async Sub LoadFolders(sf As StorageFolder)
    6. For Each childDir In Await sf.GetFoldersAsync
    7. Directory_ViewModel.Folders.Add(New Folder(childDir))
    8. Next
    9. End Sub
    10. End Class


    Ergebnis:


    Die Anzahl und der 1. Ordner stimmen, aber alle anderen Ordner haben die Eigenschaften vom letzten Ordner (hier im Ordner "Bilder") :cursing:
    @ErfinderDesRades: Hab das jetzt so gemacht:

    VB.NET-Quellcode

    1. Dim folders = Await sf.GetFoldersAsync
    2. Dim einsehbareListe As Object = folders.ToArray
    3. For Each childDir In folders
    4. Directory_ViewModel.Folders.Add(New Folder(childDir))
    5. Next


    Das Ergebnis: Alle Ordner sind Korrekt! Richtige Namen, Pfade, etc.
    Warum zur Hölle macht dann das Binding auf "Directory_ViewModel.Folders" solch einen Mist wie auf meinen Bildern darraus ;(

    @sonne75: Wo macht man das denn, konnte auf die schnelle nichts finden?