Button in Button im Code-Behind

  • WPF

Es gibt 16 Antworten in diesem Thema. Der letzte Beitrag () ist von Nofear23m.

    Button in Button im Code-Behind

    Hallo zusammen,

    ich bin absoluter Programmierneuling und erhoffe mir Hilfe in Eurem Forum. Hab jetzt ein Fernstudium zum VB-Programmierer beendet und im Betrieb ein erstes Projekt bekommen.

    Dafür habe ich in der XAML eine Reihe Checkboxen und möchte beim "checken" einer Box in einem DockPanel einen Button erzeugen. Das klappt auch schon ganz gut (habe jeder Box in XAML das Checked bzw. Unchecked-Ereignis mitgegeben). Weiterhin sollte es eine Möglichkeit geben, die Button zu versetzen. Die Idee ist, dass ich 2 weitere Button IN den jeweiligen Hauptbutton erzeuge und damit die Hauptbutton um eine Position nach links bzw. rechts versetze, also quasi die Position in der Liste verschiebe. Es gibt über die XAML auch die Möglichkeit einen Button in den Button zu legen. Leider weiss ich keine Möglichkeit, das im Code-Behind zu integrieren.

    Bisher habe ich das soweit (beim checken bzw. unchecken wird String-Liste erneuert und die Button erstellt)

    VB.NET-Quellcode

    1. Class MainWindow
    2. Private ProductList As List(Of String) = New List(Of String)
    3. Private zProduct As String = 2
    4. Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
    5. Dim First, Last As String
    6. First = "Startrodukt"
    7. Last = "Endprodukt"
    8. ProductList.Add(First)
    9. ProductList.Add(Last)
    10. ButtonErzeugen()
    11. End Sub
    12. Private Sub ChbProduct_Checked(sender As Object, e As RoutedEventArgs)
    13. Dim NewProduct As String
    14. NewProduct = sender.Content
    15. ProductList.Insert(zProduct - 1, NewProduct)
    16. zProduct += 1
    17. ButtonErzeugen()
    18. End Sub
    19. Private Sub ChbProduct_Unchecked(sender As Object, e As RoutedEventArgs)
    20. Dim DelProduct As String
    21. DelProduct = sender.Content
    22. ProductList.Remove(DelProduct)
    23. zProduct -= 1
    24. ButtonErzeugen()
    25. End Sub
    26. Private Sub ButtonErzeugen()
    27. DokPnlProducts.Children.Clear()
    28. For i = 0 To ProductList.Count - 1
    29. Dim NewProdBtn As Button = New Button
    30. With NewProdBtn
    31. .Name = ProductList(i).ToString
    32. .Content = ProductList(i).ToString
    33. .Width = 133
    34. .Height = 100
    35. .HorizontalAlignment = HorizontalAlignment.Left
    36. .VerticalAlignment = VerticalAlignment.Top
    37. End With
    38. DokPnlProducts.Children.Add(NewProdBtn)
    39. Next
    40. End Sub
    41. End Class
    Verschiedenes.
    1) du programmierst offsichtlich Strict Off, das ist eine Voreinstellung, mit der man es sich unendlich erschwert, Datentypen überhaupt richtig wahrzunehmen und zu unterscheiden.
    Was für sinnvolle Programme allerdings unerlässlich ist.
    Daher bitte: Visual Studio - Empfohlene Einstellungen

    2) Wpf ist grundsätzlich anders konzipiert, als wie du es verwendest.
    Wpf ist für den MVVM-Pattern ausgelegt - guck mal im Wpf-Tutorial-Bereich nach Tutorials zum Thema.
    Keinesfalls sollte man im CodeBehind eines Wpf-Windows Buttons zusammenbasteln.
    Dergleichen ist mit dem von Wpf bereitgestellten Instrumentarium von Databinding und Templates abzuhandeln.
    Moin,

    also, hab mir mal den Punkt 1 von Dir vorgeknöpft und beherzige das in Zukunft. Scheint ja durchaus sinnvoll zu sein. Die Tutorials werde ich mir heute mal zu Gemüte führen. Von Databinding hab ich dem Fernstudium schon mal was gehört, Templates sind neu für mich. Ich versuche mich mal daran, werde aber noch Hilfe von Euch benötigen, denke ich.

    Soweit danke erstmal für die Antwort, hilft ja auch schon, wenn man weiß, dass man falsch liegt oder es anders besser geht.
    Hab mir jetzt auch die Videoreihe von NoFear angesehen und versucht umzusetzen. Erstmal großes Kompliment an NoFear, geil gemacht und vor allem VERSTÄNDLICH!!! Und der österreichische Dialekt ist Weltklasse! :thumbsup:

    Auch habe ich jetzt Option Strict ON und muss sagen, dass gefällt mir echt gut. Da wird man gezwungen sauberen Code zu schreiben. :D

    Ich habe meinen Code umgestellt und der sieht jetzt so aus:

    Die XAML
    Spoiler anzeigen

    XML-Quellcode

    1. <Window x:Class="MainWindow"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    6. xmlns:local="clr-namespace:TestListe"
    7. mc:Ignorable="d"
    8. Title="MainWindow" Height="450" Width="800">
    9. <StackPanel>
    10. <StackPanel>
    11. <CheckBox x:Name="Prod1" Content="Produkt_1" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked"/>
    12. <CheckBox x:Name="Prod2" Content="Produkt_2" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked"/>
    13. <CheckBox x:Name="Prod3" Content="Produkt_3" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked"/>
    14. <CheckBox x:Name="Prod4" Content="Produkt_4" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked"/>
    15. <CheckBox x:Name="Prod5" Content="Produkt_5" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked"/>
    16. <CheckBox x:Name="Prod6" Content="Produkt_6" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked"/>
    17. </StackPanel>
    18. <ListBox ItemsSource="{Binding Produktliste}" Margin="10">
    19. <ListBox.ItemsPanel>
    20. <ItemsPanelTemplate>
    21. <UniformGrid Columns="8" HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
    22. </ItemsPanelTemplate>
    23. </ListBox.ItemsPanel>
    24. <ListBox.ItemTemplate>
    25. <DataTemplate>
    26. <Border Padding="5" BorderBrush="Black" BorderThickness="1">
    27. <Grid Width="60">
    28. <Grid.RowDefinitions>
    29. <RowDefinition Height="40"/>
    30. <RowDefinition Height="*"/>
    31. </Grid.RowDefinitions>
    32. <Button>
    33. <Image Source="{Binding Bildchen}" Stretch="Fill"/>
    34. </Button>
    35. <StackPanel Grid.Row="1" Orientation="Horizontal">
    36. <Button Width="30" Height="30" HorizontalAlignment="Left">
    37. <Image Source="Pictures/Zurueck_56x50.png" Stretch="UniformToFill" />
    38. </Button>
    39. <Button Width="30" Height="30" HorizontalAlignment="Right">
    40. <Image Source="Pictures/Vorwaerts_56x50.png"/>
    41. </Button>
    42. </StackPanel>
    43. </Grid>
    44. </Border>
    45. </DataTemplate>
    46. </ListBox.ItemTemplate>
    47. </ListBox>
    48. </StackPanel>
    49. </Window>



    Die Klasse
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Product
    2. Public m_Produkt As String
    3. Public m_Image As String
    4. Property Produkt As String
    5. Get
    6. Produkt = m_Produkt
    7. End Get
    8. Set(value As String)
    9. m_Produkt = value
    10. End Set
    11. End Property
    12. Property Bildchen As String
    13. Get
    14. Bildchen = m_Image
    15. End Get
    16. Set(value As String)
    17. m_Image = value
    18. End Set
    19. End Property
    20. Public Sub New(ProductClass As String, pic As String)
    21. Produkt = ProductClass
    22. Bildchen = pic
    23. End Sub
    24. Public Overrides Function ToString() As String
    25. Return $"{Produkt }"
    26. End Function
    27. End Class


    Die Public Overrides Function ToString() wäre hier nicht notwendig gewesen, da ich keinen Text übernehme.

    Das MainWindow
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Collections.ObjectModel
    2. Class MainWindow
    3. Public Property Produktliste As ObservableCollection(Of Product) = New ObservableCollection(Of Product)
    4. Private Sub CheckBox_Checked(sender As Object, e As RoutedEventArgs)
    5. Dim ProdZu As String = String.Empty
    6. Dim ProdPic As String = String.Empty
    7. If sender.GetType = GetType(CheckBox) Then
    8. ProdZu = CType(sender, CheckBox).Name.ToString
    9. ProdPic = "Pictures/" & ProdZu & ".png"
    10. End If
    11. Produktliste.Add(New Product(ProdZu, ProdPic))
    12. Me.DataContext = Me
    13. End Sub
    14. Private Sub CheckBox_Unchecked(sender As Object, e As RoutedEventArgs)
    15. Dim ProdWeg As Product
    16. For Each ProdToDel As Product In Produktliste
    17. If ProdToDel.Produkt = CType(sender, CheckBox).Name.ToString Then
    18. ProdWeg = ProdToDel
    19. End If
    20. Next
    21. Produktliste.Remove(ProdWeg)
    22. End Sub
    23. End Class



    Ich hoffe, ich habe das richtig umgesetzt. Sicherlich gibt es noch das ein oder andere zu verbessern, gute Tipps sind immer willkommen.

    Gruß aus dem schönen Mittelfranken!
    Hallo @BlackTears

    BlackTears schrieb:

    Erstmal großes Kompliment an NoFear

    Danke, nehme ich gerne an. 8o

    Das hast du auch gut umgesetzt. Der XAML ist ziemlich sauber und du hast zum großteil mit Binding gearbeitet.

    BlackTears schrieb:

    gute Tipps sind immer willkommen

    Da ich sehe das du sehr lernwillig bist und die Tipps auch annimmst, mache ich gerne ein Beispiel wie es mit reinem Binding geht so das du wirklich rein mit Binding arbeiten kannst falls es dich interessiert.

    Die MainWindow.xaml
    Spoiler anzeigen

    XML-Quellcode

    1. <Window x:Class="MainWindow"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    6. xmlns:local="clr-namespace:Test"
    7. mc:Ignorable="d"
    8. Title="MainWindow" Height="450" Width="800">
    9. <StackPanel>
    10. <ItemsControl ItemsSource="{Binding VerfuegbareProdukte}">
    11. <ItemsControl.ItemTemplate>
    12. <DataTemplate>
    13. <CheckBox Content="{Binding Produkt}" IsChecked="{Binding ProduktIsChecked}"/>
    14. </DataTemplate>
    15. </ItemsControl.ItemTemplate>
    16. </ItemsControl>
    17. <ListBox ItemsSource="{Binding Produktliste}" Margin="10">
    18. <ListBox.ItemsPanel>
    19. <ItemsPanelTemplate>
    20. <UniformGrid Columns="8" HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
    21. </ItemsPanelTemplate>
    22. </ListBox.ItemsPanel>
    23. <ListBox.ItemTemplate>
    24. <DataTemplate>
    25. <Border Padding="5" BorderBrush="Black" BorderThickness="1">
    26. <Grid Width="60">
    27. <Grid.RowDefinitions>
    28. <RowDefinition Height="40"/>
    29. <RowDefinition Height="*"/>
    30. </Grid.RowDefinitions>
    31. <Button>
    32. <Image Source="{Binding Bildchen}" Stretch="Fill"/>
    33. </Button>
    34. <StackPanel Grid.Row="1" Orientation="Horizontal">
    35. <Button Width="30" Height="30" HorizontalAlignment="Left">
    36. <Image Source="Pictures/Zurueck_56x50.png" Stretch="UniformToFill" />
    37. </Button>
    38. <Button Width="30" Height="30" HorizontalAlignment="Right">
    39. <Image Source="Pictures/Vorwaerts_56x50.png"/>
    40. </Button>
    41. </StackPanel>
    42. </Grid>
    43. </Border>
    44. </DataTemplate>
    45. </ListBox.ItemTemplate>
    46. </ListBox>
    47. </StackPanel>
    48. </Window>


    Die MainWindow.vb
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Collections.ObjectModel
    2. Imports System.ComponentModel
    3. Imports Test
    4. Class MainWindow
    5. Public Property Produktliste As ObservableCollection(Of Product) = New ObservableCollection(Of Product)
    6. Public Property VerfuegbareProdukte As ObservableCollection(Of ProductListItem) = New ObservableCollection(Of ProductListItem)(New List(Of ProductListItem) From {
    7. New ProductListItem(New Product("Prod1")),
    8. New ProductListItem(New Product("Prod2")),
    9. New ProductListItem(New Product("Prod3")),
    10. New ProductListItem(New Product("Prod4")),
    11. New ProductListItem(New Product("Prod5")),
    12. New ProductListItem(New Product("Prod6")),
    13. New ProductListItem(New Product("Prod7")),
    14. New ProductListItem(New Product("Prod8")),
    15. New ProductListItem(New Product("Prod9")),
    16. New ProductListItem(New Product("Prod10"))})
    17. Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
    18. Me.DataContext = Me
    19. VerfuegbareProdukte.ToList.ForEach(Sub(x) AddHandler x.ProduktSelectionChanged, AddressOf ProduktSelectionChanged)
    20. End Sub
    21. Private Sub ProduktSelectionChanged(newValue As Boolean, produkt As Product)
    22. If newValue Then
    23. Produktliste.Add(produkt)
    24. Else
    25. Produktliste.Remove(produkt)
    26. End If
    27. End Sub
    28. End Class
    29. Public Class ProductListItem
    30. Public Event ProduktSelectionChanged(newValue As Boolean, produkt As Product)
    31. Public Sub New(produkt As Product)
    32. Me.Produkt = produkt
    33. End Sub
    34. Public ReadOnly Property Produkt As Product
    35. Private _produktIsChecked As Boolean
    36. Public Property ProduktIsChecked As Boolean
    37. Get
    38. Return _produktIsChecked
    39. End Get
    40. Set(ByVal Value As Boolean)
    41. _produktIsChecked = Value
    42. RaiseEvent ProduktSelectionChanged(Value, Produkt)
    43. End Set
    44. End Property
    45. End Class


    Und deine Product-Klasse (nur um einen Konstruktor erweitert)
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Product
    2. Property Produkt As String
    3. Property Bildchen As String
    4. Public Sub New(ProductClass As String)
    5. Me.New(ProductClass, $"Pictures/{ProductClass}.png")
    6. End Sub
    7. Public Sub New(ProductClass As String, pic As String)
    8. Produkt = ProductClass
    9. Bildchen = pic
    10. End Sub
    11. Public Overrides Function ToString() As String
    12. Return $"{Produkt}"
    13. End Function
    14. End Class


    Schöne Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Jahaha, danke Sascha. Mal sehen, ob ich das zusammen bekomme.

    Ich werde mich mit Deinem Code auseinandersetzen, ein paar Sachen check ich, anderes muss ich noch genauer unter die Lupe nehmen.

    Bestimmt aber, habe ich noch die ein oder andere Frage dazu. Zumindest sieht das sehr geil aus, wusste nicht, dass sowas geht. Man lernt eben nie aus!

    Gruß
    Oli
    Wenn du Fragen hast kannst du dich immer an das Forum wenden.
    Es gibt keine dummen Fragen, es gibt nur dumme Antworten und/oder beratungsresistenz. Aber letzteres sehe ich bei dir mal gar nicht.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hallo Sascha,

    puuh, das war teilweise echt hart für mich und meine rudimentären Kenntnisse. Aber ich glaub ich bin dran. Ich hoffe ich habs einigermaßen verstanden:

    Du hast dem Code eine neue ObservableCollection (VerfuegbareProdukte) verpasst. Erzeugst dann eine neue Liste und fügst gleich die Items ein, indem Du zum einen eine Instanz der Klasse ProductListItem und darin eine Instanz der Klasse Product erstellst. Die Klasse Product hat einen neuen Konstruktor bekommen (der wird hier aufgerufen), der die Klasse wieder über den anderen Konstruktor aufruft (hab ich hier jetzt 2 Instanzen der Klasse?). Der Klasse ProductListItem gibst Du dann noch die Properties und das Event für das Change-Ereignis der Checkbox mit. Das Methode ProduktSelectionChanged ist klar.

    Dann das Loaded-Ereignis für das MainWindow: Die zweite Anweisung war schwierig. Mal sehen, ob ich kapiert habe. Aus der ObservableCollection Verfuegbare Produkte machst du eine Liste (.ToList) und gibst jedem Element dann das Ereignis ProduktSelectionChanged mit (For Each(sub(x) AddHandler).

    Nicht ganz klar sind die Imports System.ComponentModel und Test. Test ist der Namespace, der in der XAML definiert ist, bei mir schreibt IntelliSense in der XAML "DerNamespace "local" ist unnötig". ?(

    Da braucht man schon ein wenig Erfahrung, um sowas zu komponieren. Respekt!

    Gruß
    Oli
    Hallo Oli

    Erstmal respekt das du es wirklich durcharbeitest. Das gefällt mir gut und zeigt das du lernen willst. Finde ich sehr gut.

    BlackTears schrieb:

    Die Klasse Product hat einen neuen Konstruktor bekommen (der wird hier aufgerufen), der die Klasse wieder über den anderen Konstruktor aufruft (hab ich hier jetzt 2 Instanzen der Klasse?).

    Ne, ich rufe nur aus dem einem Konstruktor den anderen auf. Das spart mir einfach das ich den Code den ich im anderen Konstruktor habe nochmals schreibe.
    Genauso könnte ich auch folgendes machen.

    VB.NET-Quellcode

    1. Public Sub New(ProductClass As String)
    2. Produkt = ProductClass
    3. Bildchen = $"Pictures/{ProductClass}.png"
    4. End Sub
    5. Public Sub New(ProductClass As String, pic As String)
    6. Produkt = ProductClass
    7. Bildchen = pic
    8. End Sub


    Allerdings hat dies nachteile. Ändere ich etwas wie z.b. das ich hier noch weitere Properties mit Werten befüllen will oder habe ich hier logik drinnen muss ich diese dann auch wieder 2x schreiben. Darf auch nicht vegessen bei änderungen dies an der zweiten stelle auch zu ändern. Mit dem Code von mir hast du das alles immer in einem Konstruktor, und andere Konstuktoren rufen dies nur auf und geben die Parameter dann wie gewünscht mit.

    BlackTears schrieb:

    Aus der ObservableCollection Verfuegbare Produkte machst du eine Liste (.ToList) und gibst jedem Element dann das Ereignis ProduktSelectionChanged mit (For Each(sub(x) AddHandler).

    Fast, ich füge jedem Element (jeder Instanz von ProduktListItem) einen Handler hinzu. Damit jede Instanz auf das Event "horcht".

    BlackTears schrieb:

    Nicht ganz klar sind die Imports System.ComponentModel und Test. Test ist der Namespace, der in der XAML definiert ist, bei mir schreibt IntelliSense in der XAML "DerNamespace "local" ist unnötig".

    System.ComponentModel wird für die ObservableCollection benötigt. Die Vorteile gegenüber List(Of) und Observable(Of) erkläre ich in meinen Tuts.
    "Test" ist der Default Namespace der Applikation weil ich diese einfach Test benannt habe. In eine XAML wird diese automatisch eingefügt. Solange du nichts aus dem Namespace verwendet wie z.b. ein anderen UserControl oder so wird angezeigt das er nicht in Verwendung ist. Klar. Sobald du irgendwas aus dem Namespace verwendest. Converter, Behaviour, UserControls, CustomControls oder, oder, oder wird dieser Import benötigt. das ist auch der Grund warum der Namespace automatisch bei der Filegenerierung hinzugefügt wird.

    Falls du noch Fragen hast Frag bitte einfach. Es gibt keine Dummen Fragen, nur dumme Antworten. Der Anfang ist schwer, versteht man die WPF ist sie allerdings ein sehr mächtiges und cooles Werkzeug das spaß macht.
    Du gehst es aber eh richtig an indem du dir alles genau ansiehst.
    Das wichtigste ist Binding. Wenn du Binding verstehst und einzusetzen weist bist du gut unterwegs.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hallo

    Sorry, folgendes war schlecht formuliert:
    Fast, ich füge jedem Element (jeder Instanz von ProduktListItem) einen Handler hinzu. Damit jede Instanz auf das Event "horcht".


    Besser ist:
    Ich setze einen Handler für jedes Element damit ich auf das Event ProduktSelectionChanged jeder ProduktListItem-Instanz horchen kann.
    Wird in einem ProduktListItem-Objekt dieser Event geworfen wird die Prozedur ProduktSelectionChanged im MainWindow ausgeführt.

    So ist es besser formuliert denke ich.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hi Sascha,

    danke für den Nachtrag, hab das soweit verstanden. Aber jetzt:

    Wenn du Binding verstehst und einzusetzen weist bist du gut unterwegs.


    Tja, da hapert es grad noch ein wenig. Aber ich versuch es zu lernen. :/

    Damit gleich zum nächsten Kapitel:

    Ich habe meine XAML erweitert und ein TabControl außen rum gelegt.
    Spoiler anzeigen

    XML-Quellcode

    1. ​<TabControl x:Name="TabTest">
    2. <TabItem Header="Hauptseite">
    3. <StackPanel>
    4. <ItemsControl ItemsSource="{Binding VerfuegbareProdukte}">
    5. <ItemsControl.ItemTemplate>



    Dann habe ich den Code erweitert, um beim checken einer Checkbox gleich ein weiteres Tab hinzuzufügen. Das klappt auch wunderbar.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub ProduktSelectionChanged(newValue As Boolean, produkt As Product)
    2. If newValue Then
    3. Produktliste.Add(produkt)
    4. TabTest.Items.Add(produkt)
    5. Else
    6. Produktliste.Remove(produkt)
    7. TabTest.Items.Remove(produkt)
    8. End If
    9. End Sub​



    In der XAML im DataTemplate der ListBox wird u.a. einen Button definiert.
    Spoiler anzeigen

    XML-Quellcode

    1. <Button>
    2. <Image Source="{Binding Bildchen}" Stretch="Fill"/>
    3. </Button>


    Wenn jetzt der User auf den Button Klickt, soll das entsprechende TabItem in den Vordergrund geholt werden, und das mit Binding. Wird wohl gehen, nur weiss ich nicht wie. Mein Ansatz wäre auch hier ein Klasse für das Klick-Ereignis des entsprechenden Buttons zu machen.

    Spoiler anzeigen

    VB.NET-Quellcode

    1. ​Public Class ProduktTabWechsel
    2. Public Event ProduktTabInVordergrund(value As Boolean, AktProdukt As Product)
    3. Public Sub New(AktProdukt As Product)
    4. Me.Produkt = AktProdukt
    5. End Sub
    6. Public ReadOnly Property Produkt As Product
    7. Private _buttonIsClicked As Boolean
    8. Public Property ButtonIsClicked As Boolean
    9. Get
    10. Return _buttonIsClicked
    11. End Get
    12. Set(value As Boolean)
    13. _buttonIsClicked = value
    14. RaiseEvent ProduktTabInVordergrund(value, Produkt)
    15. End Set
    16. End Property
    17. End Class


    Dann die Methode im MainWindow:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. ​Private Sub ProduktTabInVordergrund(geklickt As Boolean, produkt As Product)
    2. Dim AktTabIndex As Integer = Produktliste.IndexOf(produkt)
    3. If geklickt Then
    4. TabTest.SelectedIndex = AktTabIndex
    5. End If
    6. End Sub


    Zum Schluß muss ich das ganze in der XAML noch binden, das bekomme ich nicht hin. Außerdem bin ich nicht überzeugt, dass das mit "ButtonIsClicked As Boolean" richtig ist. Weil das Klick-Ereignis gibt ja kein Boolean zurück, oder?

    Da bin ich grad noch etwas hilflos :huh: ! Kannst Du mir mal einen Ansatz verraten, ich versuch das dann gerne selbst zu lösen.

    Gruß
    Oli
    OK, also da bringst du wohl etwas durcheinander.

    ItemsSource="{Binding VerfuegbareProdukte}"
    Willst du wirklich für jedes Produkt ein Tab haben?? Ist das nur so zum Probieren oder wie? Stell dir vor du hast 150 Artikel. Uhhiiii.

    TabTest.Items.Add(produkt)
    Das ist schon die falsche richtung. Du willst ja mit Binding arbeiten. Also sprichst du schon mal vom Code aus KEIN Control an. NIE.

    Wenn die ItemsSource-Eigenschaft deines TabControl an VerfuegbareProdukte gebunden ist. Kannst du einfach dem Property VerfügbareProdukte ein Produkt hinzufügen und automatisch hast du ein weiteres Tab.
    Das ist eben die "Magie" von Binding. Da die TabItems über Binding erstellt werden, wird auch eines hinzugefügt oder entfernt wenn du das Propertie an welches es gebunden ist änderst.

    Ansonsten vertehe ich leider gerade dein vorgehen leider nicht. Du kanst aber gerne eine "Testsolution" hochladen (ohne bin-Ordner) und dazuschreiben was erreicht werden soll. Dann sehe ich mir das gerne mal an.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hallo Sascha,

    ich seh schon, da hab ich noch einiges nachzuarbeiten.

    Für Dein Verständnis: der User soll sich auf der Hauptseite (der erste Tab) einige Produkte auswählen (das sind wohl so max. 10 Stück) und dann in dem Tab für das spezifische Produkt noch Eingaben machen können oder weitere Optionen zu dem Produkt wählen können. Dann soll da einiges berechnet werden und zum Schluß eine saubere Kalkulation rauskommen. D.h ich brauch nur Tabs, für die entsprechend gewählten Produkte. Müsste ich da nicht eher die Produktliste einbinden, weil diese die gewählten Produkte repräsentiert? Und wie muss die XAML aussehen? Der erste Tab ist immer fix (Hauptseite), die anderen je nach Produkte. Der Klick auf den entsprechenden Button soll den User direkt auf die entsprechende Seite bringen. Anbei mein Projekt mit dem "falschen" Code.

    Gibts da auch Literatur dazu, also speziell WPF und Datenbindung? Deine Lernreihe muss ich wohl auch noch mal näher betrachten. Irgendwann muss ich das doch auch schnallen.

    Gruß Oli
    Dateien
    • TestListe.zip

      (3,87 MB, 171 mal heruntergeladen, zuletzt: )

    BlackTears schrieb:

    ich seh schon, da hab ich noch einiges nachzuarbeiten.

    Das wird schon, keine Sorge. Ich weis, am Anfang ist das Binding gerne mal verwirrend.

    BlackTears schrieb:

    Gibts da auch Literatur dazu, also speziell WPF und Datenbindung? Deine Lernreihe muss ich wohl auch noch mal näher betrachten. Irgendwann muss ich das doch auch schnallen.

    Schwierig. Es muss einfach "klick" machen. Ich habe ja ein paar Beispiele in meinen Tuts. Schau dir die an, probiere selbst herung und versuche einfache Bindingbeispiele zu machen. Eher simple Dinge. Wenn die Sitzen dann kompliziertere. Sonst einfach nachfragen. Kein Problem. Ich versuche es dann gerne zu erkläre wieso, weshalb und warum.

    Zurück zu deinem Beispiel:

    Wenn ich das richtig interpretiert habe sollte das Beispiel welche ich jetzt Anhänge genau das sein was du haben möchtest.
    Beachte das auch das SelectedItem syncronisiert wird. Also die Tabs mit der unteren ListBox. Das ist so ein Beispiel für etwas das outOfTheBox funktioniert wenn man mit Binding arbeitet. Klasse sache.

    Grüße
    Sascha
    Dateien
    • TestListeV1.zip

      (2,02 MB, 73 mal heruntergeladen, zuletzt: )
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Ich habe mir deinen Beitrag nochmals durchgelesen und glaube fast das du es anders haben möchtest.

    Wenn ich das richtig lese willst du den Tab mit den Verfügbaren Produkten (mit den checkboxen) und die gewählten Produkte in ein und dem selben TabControl beherbergen.

    Sprich, die Elemente innerhalb des TabControl sind nicht alle vom selben Typ.
    Auch das ist möglich, ist aber etwas "verzwickter" da man hier dann dynamischer Arbeiten muss.

    Auch hierfür habe ich schnell ein Beispiel erstellt. Aber lass dich nicht verwirren - falls dies nicht notwendig ist mach sowas erstmal nicht, das ist für den Anfang denke ich zu viel des guten.

    Grüße
    Sascha
    Dateien
    • TestListeV2.zip

      (2,15 MB, 130 mal heruntergeladen, zuletzt: )
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Alter Schwede, wo zauberst du sowas her??? Beide Lösungen sehen gut aus, allerdings schrecke ich etwas davor zurück, sowas bei mir einzubauen. Einfach aus dem Grund, weil ich es (noch) nicht verstehe. Ich glaub, ich werde Deinem Rat folgen und mich erstmal etwas einfacherem widmen, um ein wenig Erfahrung zu sammeln.

    Auf jeden Fall möchte ich bei WPF bleiben, weil ich das irgendwie besser finde als WinForm. Morgen hab ich frei, da werde ich mir mal Deine Tutorialreihe reinziehen, speziell das mit dem Binding und versuchen ein paar Sachen mit eigenen Ideen umzusetzen.

    Aber auch da werden noch Fragen offen bleiben, die werde ich dann gerne posten, da mir in dem Forum gut geholfen wird. Danke dafür nochmal.

    Und irgendwann werde ich auch Deinen Code verstehen :thumbsup: :thumbsup: .

    Gruß Oli
    Hallo Oli

    BlackTears schrieb:

    allerdings schrecke ich etwas davor zurück

    Neee, musst du nicht, ist nicht so schlimm wie es am ersten Blick aussieht. Dennoch würde ich mich an deiner Stelle an die V1 halten, die ist einfacher.
    Im Grunde hast du eine Auflistung von möglichen Produkten, und die Auflistung mit den ausgewählten Produkten.
    Wird ein Produkt ausgewählt (gecheckt) bekommst du das mit und fügt das Objekt der Auflistung hinzu. Beim abwählen eben der Auflistung entnehmen.

    Ein Tipp: Nimm einfach mal die Views komplett weg! Lass die Oberfläche bei seite. Mach nur die *.vb Dateien in VS auf und sehe sie dir an.
    Du kannst hier wenn du den Code durchgehst genau erkennen was wie und wo passiert. Wie die View das dann im endeffekt anzeigt ist völig egal. Ob das dann Checkboxen sind die du klickst, oder ob es ListBox oder ein DataGrid oder was selbst gebasteltes ist um die Elemente anzuzeigen ist auch egal. Das ist das schöne am Binding. Du kannst jederzeit die Optik und/oder die Benutzerführung anpassen ohne nur eine Zeile Code ändern zu müssen.

    BlackTears schrieb:

    Aber auch da werden noch Fragen offen bleiben, die werde ich dann gerne posten

    Dafür habe ich ja extra den "SupportThread" eingerichtet. Dieserist auch in jedem Kapitel unten verlinkt. viel Spass beim gucken und probieren. :thumbup:

    BlackTears schrieb:

    Und irgendwann werde ich auch Deinen Code verstehen

    Da bin ich mir sicher. Ansonsten Frag einfach nur. Gerne gehe ich den Code mit dir durch.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##