Anbei ein DetailView, vergleichbar dem in die vier Views (in Wpf) gegebenem und erläutertem Beispiel.
Das Viewmodel ist minimalistisch: Eine
(
Zu beachten, wie in
Nun das Xaml:
Fast der ganze Xaml-Code liegt in (
Normalerweise wird dabei der Header über dem Content angezeigt, aber noch normaler ist, dass man diesem Control ein ControlTemplate verpasst, sodass komplett anders aussieht, nämlich so, wie ich will, dass es aussieht.
In diesem Falle will ich, dass der Header links vom Content steht, deshalb habich ein horizontales
ControlTemplate
Kurz zur Erklärung: Ein
Ein sehr mächtiges Wpf-Feature.
Es ist aber auch meist enorm viel Arbeit, ein gutes ControlTemplate zu bauen - weil man sich um jedes Detail selbst kümmern muss.
Etwa beim
Egal - jdfs bei sonem
Weil
ContentPresenter
Sondern er sucht für jeden Datentyp ein geeignetes DataTemplate, und wendet das dann an.
Style
Ein
Deswegen beinhaltet ein Style vor allem
Und jeder Setter benennt die addressierte
Der Value kann ein einfacher Wert sein, dann ist so ein Setter in einer Zeile notiert.
Aber wie man sieht kann der
Also ich habe da einen
DataTemplate
Ein
Das Datatemplate der Zeilen #21-29 mappt auf
Das Datatemplate der Zeilen #30-37 mappt auf
Also fast das gleiche, nur die
Stattdessen nur der
Wie gesagt: Fast das gleiche, nur ganz was anderes.
Jo, nach so viel stylen und Templaten ist der Code für die eiglichen Controls extrem minimalistisch:
Also eine
Die
Also ein DetailView - hab ich ja gesagt
Das Werk sieht übrigens nicht unerbärmlich aus, vor allem, weil in der Listbox die File- und Directory-Infos wie KrautnRübn durcheinander herumfahren:
Das Viewmodel ist minimalistisch: Eine
ListCollectionView
, befüllt mit FileSystemInfo
s steht zur Anbindung bereit (Zeile #25).(
FileSystemInfo
- weiss man ja: die Basisklasse der überaus nützlichen Klassen FileInfo
und DirectoryInfo
):VB.NET-Quellcode
- Imports System.Collections.ObjectModel
- Imports System.IO
- Public Class MainModel
- Public Shared ReadOnly Root As New MainModel
- Private Sub New()
- Dim di = New DirectoryInfo("..\..\")
- Dim dpo = New System.Windows.DependencyObject
- If System.ComponentModel.DesignerProperties.GetIsInDesignMode(dpo) Then
- __FileSystemInfs = New ObservableCollection(Of FileSystemInfo)(New FileSystemInfo() {di.EnumerateFiles.First, di, di})
- Else
- __FileSystemInfs = New ObservableCollection(Of FileSystemInfo)(di.EnumerateFileSystemInfos("*.*", SearchOption.AllDirectories))
- End If
- FileSystemInfs = DirectCast(CollectionViewSource.GetDefaultView(__FileSystemInfs), ListCollectionView)
- End Sub
- Private Sub FileSystemInfs_CurrentChanged(sender As Object, e As EventArgs) Handles FileSystemInfs.CurrentChanged
- Dim i = FileSystemInfs.CurrentPosition
- Debug.WriteLine(If(i < 0, "leer", __FileSystemInfs(i).FullName))
- End Sub
- Public Property __FileSystemInfs As ObservableCollection(Of FileSystemInfo)
- Public WithEvents FileSystemInfs As ListCollectionView
- End Class
Sub New
zur Designzeit Dummi-Daten geladen werden (zeile #12), damit man der Xaml-Designer eine Vorschau mit Daten hat (Prinzip WYSIWYG).Nun das Xaml:
XML-Quellcode
- <Window x:Class="MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:io="clr-namespace:System.IO;assembly=mscorlib"
- Title="MainWindow" Height="350" Width="525"
- xmlns:my="clr-namespace:TemplatedDetailView"
- DataContext="{x:Static my:MainModel.Root}" WindowState="Maximized">
- <FrameworkElement.Resources>
- <Style TargetType="HeaderedContentControl">
- <Setter Property="Template">
- <Setter.Value>
- <ControlTemplate TargetType="HeaderedContentControl">
- <StackPanel Orientation="Horizontal">
- <ContentPresenter Content="{TemplateBinding Header}" Margin="0,0,5,0" />
- <ContentPresenter Content="{TemplateBinding Content}" />
- </StackPanel>
- </ControlTemplate>
- </Setter.Value>
- </Setter>
- </Style>
- <DataTemplate DataType="{x:Type io:FileInfo}">
- <Border BorderBrush="Aqua" BorderThickness="10" Padding="8" >
- <StackPanel Orientation="Vertical">
- <HeaderedContentControl Header="Name:" Content="{Binding Path=Name}"/>
- <HeaderedContentControl Header="DirectoryName:" Content="{Binding Path=DirectoryName}"/>
- <HeaderedContentControl Header="Length:" Content="{Binding Path=Length}"/>
- </StackPanel>
- </Border>
- </DataTemplate>
- <DataTemplate DataType="{x:Type io:DirectoryInfo}">
- <Border BorderBrush="#FFFAD90A" BorderThickness="10" Padding="8" VerticalAlignment="Center" >
- <StackPanel Orientation="Vertical">
- <HeaderedContentControl Header="Name:" Content="{Binding Path=Name}"/>
- <HeaderedContentControl Header="FullName:" Content="{Binding Path=FullName}"/>
- </StackPanel>
- </Border>
- </DataTemplate>
- </FrameworkElement.Resources>
- <Grid>
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="Auto" MinWidth="20" />
- <ColumnDefinition />
- </Grid.ColumnDefinitions>
- <ListBox Grid.Column="0" MinWidth="60" ItemsSource="{Binding Path=FileSystemInfs}" IsSynchronizedWithCurrentItem="True">
- <FrameworkElement.Resources>
- <DataTemplate DataType="{x:Type io:FileInfo}">
- <TextBlock Text="{Binding Name, Mode=OneWay}" Background="Aqua"/>
- </DataTemplate>
- <DataTemplate DataType="{x:Type io:DirectoryInfo}">
- <TextBlock Text="{Binding Name, Mode=OneWay}" Background="#FFFAD90A"/>
- </DataTemplate>
- </FrameworkElement.Resources>
- </ListBox>
- <ContentPresenter Grid.Column="1" Margin="10" Content="{Binding Path=FileSystemInfs/}"/>
- </Grid>
- </Window>
<FrameworkElement.Resources>
), nämlich- ein
Style
fürHeaderedContentControl
- ein
ControlTemplate
fürHeaderedContentControl
(im Style drinne) - zwei
DataTemplate
s: eines fürFileInfo
, das andere fürDirectoryInfo
- nochmal zwei DataTemplates für diese beiden "Datenklassen"
Nämlich in den lokalen Resourcen derListbox
(#46-51, schau genau!)
HeaderedContentControl
kennt nicht jeder - das ist ein Wpf-Control, was üblicherweise eine Betextung (.Header
) mit einem Wert (.Content
) verknüpft.Normalerweise wird dabei der Header über dem Content angezeigt, aber noch normaler ist, dass man diesem Control ein ControlTemplate verpasst, sodass komplett anders aussieht, nämlich so, wie ich will, dass es aussieht.
In diesem Falle will ich, dass der Header links vom Content steht, deshalb habich ein horizontales
StackPanel
ins ControlTemplate gemacht.ControlTemplate
Kurz zur Erklärung: Ein
ControlTemplate
definiert das Aussehen eines Controls komplett neu. Ein sehr mächtiges Wpf-Feature.
Es ist aber auch meist enorm viel Arbeit, ein gutes ControlTemplate zu bauen - weil man sich um jedes Detail selbst kümmern muss.
Etwa beim
Button
heisst das: Border, Background, Image, Text, etc pp. Und alles mehrfach, für die verschiedenen Zustände die ein Button haben kann: Normal, Hovered, Pressed, Focused, ... hab ich was vergessen?Egal - jdfs bei sonem
HeaderedContentControl
ist das Template wirklich einfach: je ein ContentPresenter
für die .Header
und .Content
, und gut.ContentPresenter
? Was ist das? Und wieso keinen Textblock
?Weil
Textblock
kann nur Text anzeigen, bei der FileInfo.Length (As Long)
- Property zickt der rum.ContentPresenter
ContentPresenter
kann alles - weiler nichts selbst macht.Sondern er sucht für jeden Datentyp ein geeignetes DataTemplate, und wendet das dann an.
Style
Ein
Style
ist ein Dingens, was bei einem Control die Properties setzen kann.Deswegen beinhaltet ein Style vor allem
Setter
(meist mehrere).Und jeder Setter benennt die addressierte
Property
, und gibt ihr einen Value
.Der Value kann ein einfacher Wert sein, dann ist so ein Setter in einer Zeile notiert.
Aber wie man sieht kann der
Setter.Value
auch komplex sein - gugge Zeilen #11 - 18Also ich habe da einen
Style
gebastelt für HeaderedContentControl
, mit einem Setter
für die HeaderedContentControl.Template
-Property, und der Wert den ich sette ist ein komplettes kleines ControlTemplate
(für HeaderedContentControl)DataTemplate
Ein
DataTemplate
mappt auf einen Datatype, und gibt ein (komplexes) Control an, was diesen Datatype präsentieren soll.Das Datatemplate der Zeilen #21-29 mappt auf
FileInfo
, darzustellen in einer Border
, mit StackPanel
drin, mit ... ... ... drin.Das Datatemplate der Zeilen #30-37 mappt auf
DirectoryInfo
, darzustellen in einer Border
, mit StackPanel
drin, mit ... ... ... drin.Also fast das gleiche, nur die
Border
hat eine andere Farbe, und FileInfo.DirectoryName
, .Length
werden nicht angezeigt, weil ein DirectoryInfo
hat das ja nicht.Stattdessen nur der
.FullName
Wie gesagt: Fast das gleiche, nur ganz was anderes.
Jo, nach so viel stylen und Templaten ist der Code für die eiglichen Controls extrem minimalistisch:
XML-Quellcode
- <ListBox Grid.Column="0" MinWidth="60" ItemsSource="{Binding Path=FileSystemInfs}" IsSynchronizedWithCurrentItem="True">
- <FrameworkElement.Resources>
- <!-- noch mehr DataTemplates... -->
- </FrameworkElement.Resources>
- </ListBox>
- <ContentPresenter Grid.Column="1" Margin="10" Content="{Binding Path=FileSystemInfs/}"/>
Also eine
Listbox
und ein ContentPresenter
.Die
Listbox
ist IsSynchronizedWithCurrentItem
- jo und der ContentPresenter
presentet das CurrentItem - was sonst? (schau genau, das Binding ist bischen anders als bei der ListBox!)Also ein DetailView - hab ich ja gesagt
Das Werk sieht übrigens nicht unerbärmlich aus, vor allem, weil in der Listbox die File- und Directory-Infos wie KrautnRübn durcheinander herumfahren:
Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()