Treeview mit Spalten + StringFormat

    • WPF

      Treeview mit Spalten + StringFormat

      Weil mein Plattenplatz knapp wird, wollte ich mir einen Überblick verschaffen, welches die größten Ordner sind.

      Ist ganz nett - man wählt einen Ordner, und kriegt alle Unterordner der Größe nach sortiert serviert. Die größten Ordner kann man dann weiter-öffnen, und so kann man recht einfach Ordner auffinden, die aufzuräumen vlt. lohnenswert ist.

      Jedenfalls hier solls ja um zwei Wpf-Features gehen, um die SharedSizeGroups und ums StringFormat.
      Das Xaml:

      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:my="clr-namespace:SizeBrowser"
      5. xmlns:hlp="clr-namespace:System.Windows.Controls;assembly=WpfHelpers"
      6. DataContext="{Binding Source={StaticResource Mainmodel}}"
      7. Title="{Binding Path=Directory.FullName}">
      8. <hlp:GridEx RowDefs="auto,">
      9. <Menu>
      10. <MenuItem Header="Load" Command="{Binding Path=FillCommand}" />
      11. </Menu>
      12. <TreeView hlp:GridEx.Range="2" ItemsSource="{Binding Path=TopLevels}"
      13. Grid.IsSharedSizeScope="True">
      14. <ItemsControl.ItemTemplate>
      15. <HierarchicalDataTemplate DataType="{x:Type my:DirectoryNode}"
      16. ItemsSource="{Binding Path=Childs}">
      17. <Grid>
      18. <Grid.ColumnDefinitions>
      19. <ColumnDefinition SharedSizeGroup="FirstCol" Width="Auto" />
      20. <ColumnDefinition SharedSizeGroup="SecondCol" />
      21. </Grid.ColumnDefinitions>
      22. <TextBlock Text="{Binding Path=Name}" />
      23. <!--
      24. <TextBlock Text="{Binding Path=Size, StringFormat= Dieser Ordner hat \{0:#\,0\} Bytes}"
      25. Margin="10,0,0,0" Grid.Column="1" VerticalAlignment="Bottom" />
      26. -->
      27. <TextBlock Text="{Binding Path=Size, StringFormat= {}{0:#\,0}}"
      28. Margin="10,0,0,0" Grid.Column="1" FontFamily="Courier New"
      29. HorizontalAlignment="Right" VerticalAlignment="Bottom" />
      30. </Grid>
      31. </HierarchicalDataTemplate>
      32. </ItemsControl.ItemTemplate>
      33. </TreeView>
      34. </hlp:GridEx>
      35. </Window>
      Also es ist ein Window mit einem Grid mit einem Treeview.

      SharedSizeGroup
      Der Treeview hat die AttachedProperty Grid.IsSharedSizeScope gesetzt (Zeile#13), und im HierarchicalTemplate gibts (scheinbar) ein Grid (#17), dessen ColumnDefinitions .SharedSizeGroup gesetzt haben.
      Und das ist es auch schon zum Thema Spalten im Treeview.
      Scheinbar(!!) ist das nur ein Grid im HierarchicalTemplate, aber weil es auf alle DirectoryNodes angewendet wird, entstehen zur Laufzeit überaus viele Grids. Gewünscht ist aber, dass die ersten Spalten aller dieser Grids gleich breit sind.
      Jo, und das geht eben mit den SharedSizeGroups. Der Treeview hat den SharedSizeScope, und alle Grids innerhalb dessen können an gemeinsamen SharedSizeGroups teilnehmen.
      Das ist jetzt so gemacht, dass die erste Column als Breite Auto hat (#19), sodass die erste Spaltenbreite durch die maximale Breite des ersten Textblocks im Grid (#22) bestimmt wird. Die zweite Spalte hat keine Breiten-Definition - dann steht sie defaultmäßig auf Stretch.

      Der zweite Textblock (#27) hat den nicht-proportionalen Font Courier New sowie HorizontalAlignment.Right, sodass die Ziffern der Zahlen einer Treeview-Ebene entsprechend ihres Stellenwertes untereinander stehen.

      StringFormat
      Hier betrachten wir zunächst den auskommentierten Textblock, den versteht man leichter:

      XML-Quellcode

      1. <TextBlock Text="{Binding Path=Size, StringFormat= Dieser Ordner hat \{0:#\,0\} Bytes}"
      2. Margin="10,0,0,0" Grid.Column="1" VerticalAlignment="Bottom" />
      Das StringFormat ist innerhalb des Bindings notiert, ist also ein String im String. Genau heraus-isoliert lautet es: Dieser Ordner hat \{0:#\,0\} Bytes.
      Genau diesen Format-String könnte man auch der herkömmlichen String.Format() - Methode übergeben, etwa:

      VB.NET-Quellcode

      1. dim s = String.Format("Dieser Ordner hat {0:#,0} Bytes", 123456)
      und erhielte die gleiche Ausgabe:

      Ausgabe schrieb:

      Dieser Ordner hat 123,456 Bytes
      Da im Xaml aber die Zeichen { , } Syntax bedeuten, sind sie in der Xaml-Variante durch vorangestelltes \ escaped - das ist auch schon der ganze Unterschied zur String.Format() Format-String-Syntax.
      Hier Bildle, wie jeder DirectoryNode die genannte Ausgabe generiert - also die Zahl (inklusive Tausender-Trennzeichen) in anderen Text eingebettet:


      Ist natürlich suboptimal, also die in Bild#1 gezeigte Zahlendarstellung ohne Einbettung ist günsiger, mit {}{0:#\,0} als Format-String.
      Hier gibt es aber eine Eigentümlichkeit, nämlich die {} zu Beginn.
      Tja, diese Schrulle ist bei StringFormaten ohne Einbettung leider erforderlich, da der Xaml-Parser ansonsten Spaces links der Platzhalter-Klammer {0:#\,0} nicht eindeutig zuordnen kann: Als XamlCode würden Spaces übergangen, als Bestandteil des FormatStrings hingegen wären sie umgebender Text, in den die Zahl einzubetten ist.
      Und deshalb muss bei StringFormat-FormatStrings ohne den Platzhalter umgebenden Text der Anfang mit {} markiert sein.
      Dateien
      • SizeBrowser.zip

        (90,23 kB, 295 mal heruntergeladen, zuletzt: )

      Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von „ErfinderDesRades“ ()