Visibility von TabControl TabItems (MVVM)

  • WPF

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von Dksksm.

    Visibility von TabControl TabItems (MVVM)

    Hallo,

    ein TabControl TabItem bekommt man durch Datenbindung auf das TabItem mit Visibility="{Binding MeineTabItemVisibility}" sichtbar oder nicht sichtbar, denkt jemand wie ich, der von WinForms kommt.
    So einfach ist es natürlich *grins* unter WPF nicht. Den Inhalt des TabItems habe ich dann auch mit der selben Bindung unsichtbar gemacht, was auch ging... für den Inhalt.
    Der Header wurde noch immer dargestellt. Dann dachte ich mir, okay ich bin ja nicht ganz dumm, also habe ich den Headertext auch mit einer Bindung auf String.Empty bzw. auf den gewünschten Text gesetzt.

    Das Ausblenden des Tabs samt Header funktioniert nun auch wie es soll, aber ich bekomme den Header nicht mehr angezeigt. Das ist natürlich extrem blöd für mich.

    Hat jemand eine Idee, wie ich das vernünftig steuern kann? Ich verstehe auch nicht wirklich, warum man Header und Content hier nicht gemeinsam ausblenden oder einblenden kann.
    Ich habe es mit Visibility.Hidden und mit Visibility.Collapsed versucht, das Ergebnis unterscheidet sich nicht.

    Gruß
    Rob
    Hallo

    Nur um Missverständnisse aus dem Weg zu räumen und der Möglichkeit das wir aneinander vorbeireden wäre ein bischen XAML und die Klasse auf die das Visibility gebunden ist sicher Hilfreich. Lade die mal hoch. Denn normalerweise ist das mit dem ausblenden von Tabitems nämlich überhaupt kein Problem.

    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

    du kannst ja folgendes mal in dein MainWindow einfügen:

    XML-Quellcode

    1. <Window.Resources>
    2. <local:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
    3. </Window.Resources>
    4. <Grid>
    5. <StackPanel>
    6. <TabControl Height="150">
    7. <TabItem Header="Tab1" Content="Content1" Visibility="{Binding IsChecked, Converter={StaticResource BooleanToVisibilityConverter}, ElementName=chkTab1}"/>
    8. <TabItem Header="Tab2" Content="Content2" Visibility="{Binding IsChecked, Converter={StaticResource BooleanToVisibilityConverter}, ElementName=chkTab2}"/>
    9. <TabItem Header="Tab3" Content="Content3" Visibility="{Binding IsChecked, Converter={StaticResource BooleanToVisibilityConverter}, ElementName=chkTab3}"/>
    10. <TabItem Header="Tab4" Content="Content4" Visibility="{Binding IsChecked, Converter={StaticResource BooleanToVisibilityConverter}, ElementName=chkTab4}"/>
    11. </TabControl>
    12. <StackPanel Orientation="Horizontal">
    13. <CheckBox x:Name="chkTab1" Content="Tab 1 Visibility" IsChecked="True" Margin="5,0"/>
    14. <CheckBox x:Name="chkTab2" Content="Tab 2 Visibility" IsChecked="True" Margin="5,0"/>
    15. <CheckBox x:Name="chkTab3" Content="Tab 3 Visibility" IsChecked="True" Margin="5,0"/>
    16. <CheckBox x:Name="chkTab4" Content="Tab 4 Visibility" IsChecked="True" Margin="5,0"/>
    17. </StackPanel>
    18. </StackPanel>
    19. </Grid>



    Und hier der Code vom Converter:

    VB.NET-Quellcode

    1. Public Class BooleanToVisibilityConverter
    2. Implements IValueConverter
    3. Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert
    4. If CBool(value) Then
    5. Return Visibility.Visible
    6. Else
    7. Return Visibility.Collapsed
    8. End If
    9. End Function
    10. Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.ConvertBack
    11. Throw New NotImplementedException()
    12. End Function
    13. End Class



    Funzt tadellos. Meine vermutung. Du setzt Visibility gleich mit Boolean. In Winforms gibt es ja IsVisible vom Typ Boolean. In der WPF gibt es 3 Möglichkeiten.
    Sichtbar :: Unsichtbar und der Platz wird Reserviert :: Unsichtbar und der Platz wird nicht Reserviert

    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 @Nofear23m

    erst mal ein völlig neu erstelltes Beispiel, mit dem ich mein Problemn verdeutliche.
    Nein, ich habe nicht mit Boolean herumexperimentiert, siehe meinen letzten Satz im Eingangspost. Ich weiß schon was die Visibility Attribute sind und was sie bedeuten.

    Ich mach mich gleich dran und baue das Beispiel nach deinen aktuellen Vorschlag um. Danke dafür :)

    WpfTabItemVisibility.zip

    Grüße
    Rob

    Nachtrag: Ich habe das jetzt mit dem Converter umgesetzt und habe immer noch das selbe Problem.
    Ich bekomme die TabHeader nicht "weg", sehr wohl aber den Content (UserControl).

    Mit den Checkboxen kann ich natürlich so nicht arbeiten. Begreifen tu ich es nicht.
    Hier die neue Solution WpfTabItemVisibility00.zip

    Grüße
    Rob

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Dksksm“ ()

    Hallo @r0tzi

    Dann kann ich aber auch gleich bei WinForms bleiben. Ich möchte das schon nach MVVM Pattern haben.

    Ausserdem ich kann die Tab ja auch unsichtba machen, in dem ich den Header auf String.Empty setze. ABER ich kann dannach den Header setzen wie ich will, sichtbar wird er dann nicht mehr :(
    Das ist auch völlig unabhängig von Styles. Ich probe da schon gute 2 Tage drann herum, mit und ohne Styles (MahApps komplett entfernt).
    Habe neue Beispielanwendungen erstellt nach @Nofear23ms vorgaben. Es ist immer das selbe Ergebnis.


    Grüße
    Rob

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Dksksm“ ()

    Hallo Leute. Mal langsam mit den jungen Pferden.

    @r0tzi Nene, sowas fangen wir uns gar nicht erst an. 8o Abgesehen davon ist dies nicht die Aufgabenstellung. Die Aufgabe war es unsichtbar zu machen. Selbiges gilt für @Yanbel.
    Oft ist es von nöten es "nur" unsichtbar zu machen um (wenn es wieder hinzugefügt werden soll) nicht vieleicht alle daran gebundenen Daten wieder initialisieren zu müssen.

    So, nun zum Problem. Ich sag es eh oft. Behaltet die Console im Auge!

    Folgende Ausgaben sehe ich da:
    System.Windows.Data Error: 40 : BindingExpression path error: 'MainVisible' property not found on 'object' ''MainViewModel' (HashCode=16578980)'. BindingExpression:Path=MainVisible; DataItem='MainViewModel' (HashCode=16578980); target element is 'TabItem' (Name='Hauptformular'); target property is 'Visibility' (type 'Visibility')

    Was ja auch korrekt ist. Das MainViewModel hat kein Property mit diesem Namen. Nur ein Property Worker vom Typ WorkerViewModel.
    WorkerViewModel jedoch hat ein Property mit dem Namen.

    Tja, und wenn das Binding nicht hinhaut, wird auch nichts unsichbar/sichtbar.

    XML-Quellcode

    1. <TabControl Height="Auto" Grid.Row="0" DataContext="{Binding Worker}">

    Behebt den Fehler. Der Datencontext ist dann für das TabControl auf Worker gesetzt. So muss nun auch nicht Worker für jedes UserControl als DatenKontext gesetzt werden.

    Der ganze XAML also wie folgt:
    Spoiler anzeigen

    XML-Quellcode

    1. <Window x:Class="WpfTabItemVisibility.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:WpfTabItemVisibility"
    7. xmlns:viewmodel="clr-namespace:ViewModel"
    8. mc:Ignorable="d"
    9. Title="MainWindow" Height="350" Width="525">
    10. <Window.DataContext>
    11. <viewmodel:MainViewModel/>
    12. </Window.DataContext>
    13. <Window.Resources>
    14. <viewmodel:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
    15. </Window.Resources>
    16. <Grid>
    17. <Grid.RowDefinitions>
    18. <RowDefinition Height="*"/>
    19. <RowDefinition Height="44" />
    20. </Grid.RowDefinitions>
    21. <TabControl Height="Auto" Grid.Row="0" DataContext="{Binding Worker}">
    22. <TabItem x:Name="Hauptformular" Header="Hauptformular" Visibility="{Binding MainVisible, Converter={StaticResource BooleanToVisibilityConverter}}">
    23. <Grid Background="White">
    24. <local:ucMain x:Name="GP" DataContext="{Binding}" Visibility="{Binding MainVisible, Converter={StaticResource BooleanToVisibilityConverter}}"/>
    25. </Grid>
    26. </TabItem>
    27. <TabItem x:Name="ZusatzTab" Header="Zusatz Tab" Visibility="{Binding SecondVisible, Converter={StaticResource BooleanToVisibilityConverter}}">
    28. <Grid Background="White">
    29. <local:ucSecond DataContext="{Binding}" Visibility="{Binding SecondVisible, Converter={StaticResource BooleanToVisibilityConverter}}"/>
    30. </Grid>
    31. </TabItem>
    32. <TabItem x:Name="OpenFileTab" Header="Datei wählen">
    33. <Grid Background="White">
    34. <local:ucThird DataContext="{Binding}" Margin="0,0,0,0"/>
    35. </Grid>
    36. </TabItem>
    37. </TabControl>
    38. <StatusBar Grid.Row="1" DataContext="{Binding Status}" Grid.ColumnSpan="2">
    39. <StatusBar.ItemsPanel>
    40. <ItemsPanelTemplate>
    41. <Grid VerticalAlignment="Bottom">
    42. <Grid.RowDefinitions>
    43. <RowDefinition Height="20" />
    44. <RowDefinition Height="24" />
    45. </Grid.RowDefinitions>
    46. </Grid>
    47. </ItemsPanelTemplate>
    48. </StatusBar.ItemsPanel>
    49. <StatusBarItem Grid.Column="0" HorizontalContentAlignment="Stretch">
    50. <ProgressBar x:Name="SBarProgress" Minimum="0" Maximum="100" Value="{Binding StatusProgress}" Visibility="{Binding StatusProgessVisibility}" IsIndeterminate="{Binding StatusProgessMarquee}" Height="12" Margin="5,0"/>
    51. </StatusBarItem>
    52. <StatusBarItem x:Name="SbarUserNote" Grid.Row="1" Content="{Binding StatusText}" Margin="5,0" VerticalContentAlignment="Top"/>
    53. </StatusBar>
    54. </Grid>
    55. </Window>



    Wenn Fragen diesbezüglich auftauchen gerne her damit.

    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 @Nofear23m

    puh, ich habe die Console zwar auf, aber zu klein offensichtlich, ich brauch mehr Bildschirme ;)
    Nee, Du hast ja Recht, mit der Änderung im XAML war sofort alles gut, man hat's direkt im Designer gesehen^^

    Nun läufts wie es soll.
    Erste Frage: DataContext="{Binding}" übernimmt das binding vom übergordneten Control?
    Zweite Frage: kann ich über XAML ein TabControl Item aktivieren? Wenn ja, wie?

    Grüße und nochmal vielen Dank
    Rob

    Dksksm schrieb:

    Erste Frage: DataContext="{Binding}" übernimmt das binding vom übergordneten Control?

    Ja, ist das selbe wie wenn KEIN Binding angegeben wird. Der DatenKontext wird immer vererbt. Ich gebe es allerdings gerne an da ich dann auf einen Blick sehe auf was ich gebunden habe.

    Dksksm schrieb:

    Zweite Frage: kann ich über XAML ein TabControl Item aktivieren? Wenn ja, wie?

    Jein. Ja und Nein. Kommt darauf an wie du es machen willst. Was willst du denn als "Trigger" dafür haben? Also wie soll es aktiviert werden? Was ist die Bedingung?

    PS: Wenn ein Binding nicht funktioniert häng einen "FakeConverter" dran. Ist so ein kleiner Trick von mir.

    VB.NET-Quellcode

    1. Public Class BindingDebuggerConverter
    2. Implements IValueConverter
    3. Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert
    4. Return value
    5. End Function
    6. Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.ConvertBack
    7. Return value
    8. End Function
    9. End Class

    Da kann ich bei Return value nen Haltepunkt setzen und sehe genau welches Objekt hier reinkommt. :thumbup:

    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. ##