TreeViewItem Visibility und MultiBinding

  • WPF

Es gibt 4 Antworten in diesem Thema. Der letzte Beitrag () ist von KillaChris.

    TreeViewItem Visibility und MultiBinding

    Hallo,

    ich arbeite gerade an einem Baum in WPF. Im Grunde bin ich schon soweit fertig, ich habe nur noch ein kleines Problem.

    Im Hintergrund pflege ich ein Objekt, welches den Baum beinhaltet. Dargestellt wird dieser eine Baum aber auf zwei Oberflächen.
    Nun kann es sein, dass auf der einen Oberfläche eine Option gesetzt wird, welche ein paar TreeViewItems "ausblendet".

    Mein Problem ist nun, dass sich der Baum dadurch auf beiden Oberflächen verändert. Dies wollte ich nun durch MultiBinding und einen Converter verhindern.
    Mein Code sieht folgendermaßen aus:

    VB.NET-Quellcode

    1. Public Class ShowSegmentConverter
    2. Implements IMultiValueConverter
    3. Public Function Convert(value() As Object, targetType As Type, parameter As Object, culture As System.Globalization.CultureInfo) As Object Implements IMultiValueConverter.Convert
    4. If CBool(value(0)) Then
    5. Return System.Windows.Visibility.Visible
    6. Else
    7. Dim s As Segment = GlobSegmentTree.GetSegment(CLng(value(1)))
    8. Return s.Enabled
    9. End If
    10. End Function
    11. Public Function ConvertBack(value As Object, targetTypes() As Type, parameter As Object, culture As System.Globalization.CultureInfo) As Object() Implements IMultiValueConverter.ConvertBack
    12. Throw New NotSupportedException("This method should never be called")
    13. End Function
    14. End Class


    Hier das nötige XAML:

    XML-Quellcode

    1. <TreeView.ItemContainerStyle>
    2. <Style TargetType="{x:Type TreeViewItem}">
    3. <Setter Property="IsExpanded" Value="{Binding IsExpanded}"/>
    4. <!--<Setter Property="Visibility" Value="{Binding Enabled}"/>-->
    5. <Setter Property="Visibility">
    6. <Setter.Value>
    7. <MultiBinding Converter="{StaticResource ShowSegmentConverter}" Mode="OneWay">
    8. <Binding ElementName="IsAssignCheckBox" Path="IsChecked"/>
    9. <Binding Path="Id"/>
    10. </MultiBinding>
    11. </Setter.Value>
    12. </Setter>
    13. <Setter Property="Background" Value="Transparent"/>


    Ich überprüfe praktisch ob eine CheckBox gesetzt ist, falls dies der Fall ist (Oberfläche 1) wird immer visible zurückgegeben. Falls die CheckBox nicht gesetzt ist (Oberfläche 2), wird anhand der Id, welche an das TreeViewItem gebunden ist das Objekt aus dem Baum geholt und die Tatsächliche Eigenschaft des Objekts zurückgegeben. Sprich meistens Visibilty.Collapsed.
    Seitdem ich den Converter verwende werden die TreeViewItems aber gar nicht mehr ausgeblendet. Egal ob in dem Beispiel value(0) true oder false ist.

    Bevor ich diesen Converter verwendet habe, habe ich es ganz schlich per Binding gelöst, wie in der auskommentieren Zeile zusehen ist. Aber dann ändern sich wie gesagt beide Oberflächen, was eigentlich nicht so sein soll.
    Ich habe den Converter ja schonmal debuggt. Da läuft leider alles richtig.
    Für jedes Item in meinem TreeView wird die richtige Id übergeben.

    Ja ich habe am Anfang versucht das über die Eigenschaft Enabled zu lösen, dann waren die Items aber nur ausgegraut, deswegen heißt es noch Enabled. Enabled gibt aber entweder ein Visibility.Collapsed oder ein Visibility.Visible zurück.
    Das ist es ja leider was mich so stutzig macht, es wird häufig ein Collapsed zurückgegeben, auf der Oberfläche wird aber leider nichts ausgeblendet.

    Edit:

    Was ich jetzt mal herausgefunden habe:
    Ich habe ungefähr 150 Items im TreeView.

    Wenn sich nun Enabled ändert, dann wird das bei jedem Item angepasst und das PropertyChanged-Event geworfen. Also sollte er mir in den Converter eigentlich auch 150 mal reingkommen.
    Ich hab das jetzt mal gezählt. Er kommt leider nur in etwa 10 mal rein.

    Edit2:

    Gelöst. Man musste sich bei MultiBinding als 3. Parameter an Enabled binden. Dann kommt er auch jedesmal wenn das PropertyChanged-Event für Enabled geworfen wird in den Converter rein und dann funktioniert es. Auch wenn man im Converter den Wert von Enabled gar nicht mehr benötigt. Muss man wohl leider übergeben, damit sich die Oberfläche aktualisiert.

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

    keine Ahnung.
    Bei mir funzt das:

    XML-Quellcode

    1. <TreeView x:Name="tv" hlp:GridEx.Range="b1" ItemsSource="{Binding Path=ChildNodes}" MouseDoubleClick="Close_Me" >
    2. <FrameworkElement.Resources>
    3. <my:ShowSegmentConverter x:Key="ShowSegmentConverter"/>
    4. </FrameworkElement.Resources>
    5. <TreeView.ItemTemplate>
    6. <HierarchicalDataTemplate DataType="{x:Type my:DirectoryNode}" ItemsSource="{Binding Path=ChildNodes}">
    7. <StackPanel Orientation="Horizontal">
    8. <Image Width="{Binding ElementName=FontRatio, Path=[1.5]}" Source="{Binding Path=Image}" />
    9. <TextBlock Text="{Binding Path=Name, StringFormat={} {0}}" VerticalAlignment="Center" />
    10. </StackPanel>
    11. </HierarchicalDataTemplate>
    12. </TreeView.ItemTemplate>
    13. <TreeView.ItemContainerStyle>
    14. <Style TargetType="{x:Type TreeViewItem}">
    15. <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
    16. <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
    17. <Setter Property="Visibility">
    18. <Setter.Value>
    19. <MultiBinding Converter="{StaticResource ShowSegmentConverter}" Mode="OneWay">
    20. <Binding ElementName="ckVisible" Path="IsChecked"/>
    21. <Binding Path="Parent"/>
    22. </MultiBinding>
    23. </Setter.Value>
    24. </Setter>
    25. </Style>
    26. </TreeView.ItemContainerStyle>
    27. </TreeView>
    28. <DockPanel hlp:GridEx.Range="2">
    29. <Button Content="Ok" IsDefault="True" Margin="5" Padding="10,0,11,1" Click="Close_Me" />
    30. <Button DockPanel.Dock="Right" Content="Cancel" IsCancel="True" Margin="5" Click="Close_Me"/>
    31. <TextBlock Text="{Binding Path=SelectedNode.Fullname}" VerticalAlignment="Center" TextWrapping="Wrap" />
    32. <CheckBox Name="ckVisible" IsChecked="True" />
    33. </DockPanel>

    VB.NET-Quellcode

    1. Public Class ShowSegmentConverter
    2. Implements IMultiValueConverter
    3. Public Function Convert(value() As Object, targetType As Type, parameter As Object, culture As System.Globalization.CultureInfo) As Object Implements IMultiValueConverter.Convert
    4. If Not CBool(value(0)) AndAlso value(1) IsNot Nothing Then
    5. Return System.Windows.Visibility.Hidden
    6. End If
    7. Return System.Windows.Visibility.Visible
    8. End Function
    9. Public Function ConvertBack(value As Object, targetTypes() As Type, parameter As Object, culture As System.Globalization.CultureInfo) As Object() Implements IMultiValueConverter.ConvertBack
    10. Throw New NotSupportedException("This method should never be called")
    11. End Function
    12. End Class
    Das versteckt ggfs. alle Nodes, die einen Parent haben.
    Eventuell hat das bei mir so nicht geklappt, weil ich die Enabled (also bei mir Visibility Eigenschaft) im Code ändere.
    Man kann in einem anderen Fenster, gewisse Objekte auswählen und je nachdem welches Objekt ausgewählt ist, sollen die Ordner, in welchen sich das Objekt nicht befindet ausgeblendet werden.

    Aber nichts desto trotz, wenn ich die Enabled Eigenschaft an den Converter übergebe dann aktualisiert sich die GUI auch richtig.