21.6 Weitere Steuerelemente
21.6.1 Das Steuerelement »ToolTip«
Es ist guter Stil in Windows-Anwendungen, Zusatzinformationen über kleine Rechtecke bereitzustellen, die als Tooltips bezeichnet werden. Angezeigt werden Tooltips immer dann, wenn die Maus sich über einem Steuerelement oder einer Komponente befindet und eine Weile nicht bewegt wird. Jeder Komponente kann ein eigener Tooltip zugeordnet werden. Dazu dient die Eigenschaft ToolTip der Komponenten. Im einfachsten Fall kann ein ToolTip-Element wie im folgenden Listing gezeigt festgelegt werden:
<StackPanel>
<Button Height="40" Width="150">
Beenden
<Button.ToolTip>
Hiermit schließen Sie das Fenster
</Button.ToolTip>
</Button>
</StackPanel>
Listing 21.44 Eine Schaltfläche mit einem zugeordneten »ToolTip«
Sie können aber die Fähigkeiten der WPF nutzen und den Inhalt der ToolTip-Eigenschaft frei definieren. Im folgenden Listing wird dazu ein StackPanel verwendet, das seinerseits ein Label- und ein TextBlock-Element enthält.
<StackPanel>
<Button Height="40" Width="150">
Beenden
<Button.ToolTip>
<StackPanel>
<Label FontSize="14" HorizontalAlignment="Center" Foreground="Red"
FontWeight="Bold">Achtung!</Label>
<TextBlock MaxWidth="250" TextWrapping="Wrap">Durch Klicken dieser
Schaltfläche wird das Fenster geschlossen und alle
Änderungen gehen verloren.
</TextBlock>
</StackPanel>
</Button.ToolTip>
</Button>
</StackPanel>
Listing 21.45 Komplexer »ToolTip« für eine Schaltfläche
Abbildung 21.23 Button mit »ToolTip«-Steuerelement aus Listing 21.45
Sie können die Anzeige des ToolTips nach eigenem Ermessen konfigurieren. Dazu verwenden Sie die Klasse ToolTipService. Mit deren Hilfe können Sie beispielsweise mit der Eigenschaft ShowDuration die Anzeigedauer festlegen und mit InitialShowDelay die Verzögerung, bis ein Tooltip angezeigt wird. Die Zeitangaben erfolgen in Millisekunden.
Standardmäßig erfolgt die Anzeige des Tooltips beim Mauszeiger, kann aber mit den Eigenschaften HorizontalOffset, VerticalOffset, PlacementTarget und PlacementRectangle auch nach eigenen Vorstellungen eingestellt werden. Auch diese Eigenschaften stellen Sie mit ToolTipService direkt im betreffenden Element ein.
<Button Height="40" Width="150"
ToolTipService.ShowDuration="3000"
ToolTipService.InitialShowDelay="500">
Beenden
[...]
</Button>
Listing 21.46 »ToolTip« individuell einstellen mit »ToolTipService«
21.6.2 Die »Progressbar«
Das Element ProgressBar dient dazu, den Benutzer bei einer lang andauernden Verarbeitung über den aktuellen Fortschritt zu informieren. Die wichtigsten Eigenschaften sind schnell genannt: Minimum beschreibt den Minimalwert, Maximum den Maximalwert, und Value bestimmt die aktuelle Position.
<ProgressBar Minimum="0" Maximum="100" Value="35" Height="25"/>
Listing 21.47 Definition eines »ProgressBar«-Controls
Eine interessante Eigenschaft der ProgressBar soll nicht unerwähnt bleiben: IsIndeterminate. Sie können diese Eigenschaft auf true festlegen, wenn die aktuelle Fortschrittsposition nicht festzustellen bzw. unbekannt ist. In diesem Fall werden die drei Eigenschaften Minimum, Maximum und Value ignoriert, und anstelle des Fortschrittsbalkens wird eine Animation angezeigt.
21.6.3 Das Steuerelement »Slider«
Mit dem Slider-Steuerelement kann der Anwender einen bestimmten Wert einstellen. Zur Festlegung des minimalen und maximalen Werts dienen auch hier die Eigenschaften Minimum und Maximum, die Eigenschaft Value beschreibt den aktuellen Wert. Mit der Eigenschaft TickFrequency können Sie eine Hilfsskala einblenden, die mit TickPlacement am Slider ausgerichtet werden kann. Der an TickFrequency zugewiesene Wert beschreibt den Abstand der Hilfslinien. Mit der Eigenschaft IsSnapToTickEnabled=true bewirken Sie, dass der Anwender nicht einen beliebigen Wert einstellen kann, sondern nur Werte, die durch die Hilfslinien vorgegeben werden. Der Schieberegler rastet also ein.
<Slider TickFrequency="5" TickPlacement="BottomRight" Minimum="0"
Maximum="100" IsSnapToTickEnabled="True"></Slider>
Listing 21.48 Das Steuerelement »Slider« im XAML-Code
Abbildung 21.24 Das »Slider«-Steuerelement
Normalerweise wird der Minimalwert links und der Maximalwert rechts angezeigt. Mit IsDirectionReversed kann die Ausrichtung umgedreht werden.
Klickt der Anwender links oder rechts vom Schieberegler, wird zum aktuellen Wert der unter LargeChange eingestellte Wert addiert bzw. subtrahiert. Soll stattdessen die exakte Klickposition zur Festlegung des neuen Wertes herangezogen werden, ist die Eigenschaft IsMoveToPointEnabled auf True einzustellen.
21.6.4 Das »GroupBox«-Steuerelement
Bei der GroupBox handelt es sich um ein Steuerelement, das mehrere andere Steuerelemente visuell zusammenfassen kann. Der Inhalt einer GroupBox wird durch die Eigenschaft Content beschrieben. Dabei kann es sich um einen Layout-Container handeln, so dass im Grunde genommen beliebig viele Elemente zugeordnet werden können.
Eine GroupBox kann eine Beschriftung aufweisen. Dazu dient die Eigenschaft Header. Natürlich kann Header seinerseits auch durch ein Steuerelement beschrieben werden.
Der folgende XAML-Code zeigt GroupBox-Elemente. Das untere hat ein CheckBox-Element in der Eigenschaft Header.
<Grid>
<Grid.RowDefinitions>
<RowDefinition /><RowDefinition />
</Grid.RowDefinitions>
<GroupBox Grid.Row="0" Header="Schriftstil" BorderThickness="2" BorderBrush="Black">
<StackPanel>
<CheckBox>Fett</CheckBox>
<CheckBox>Kursiv</CheckBox>
<CheckBox>Unterstrichen</CheckBox>
</StackPanel>
</GroupBox>
<GroupBox Grid.Row="1" BorderThickness="2" BorderBrush="Black">
<GroupBox.Header>
<CheckBox>Aktivierung</CheckBox>
</GroupBox.Header>
<StackPanel>
<TextBox Margin="5"></TextBox>
<TextBox Margin="5"></TextBox>
</StackPanel>
</GroupBox>
</Grid>
Listing 21.49 Definition von zwei »GroupBox«-Elementen
Abbildung 21.25 Zwei »GroupBox«-Steuerelemente
21.6.5 Das Steuerelement »ScrollViewer«
Einige WPF-Steuerelemente sind zwar in der Lage, einen umfangreichen Inhalt anzuzeigen, unterstützen aber leider keine Rollbalken. Dieses Manko kann durch das Steuerelement ScrollViewer behoben werden. Ein ScrollViewer zeigt Rollbalken an, sobald der Inhalt eines Elements größer wird als sein Anzeigebereich und die beiden Eigenschaften
- HorizontalScrollBarVisibility und
- HorizontalScrollBarVisibility
auf Visible eingestellt sind.
Eine Reihe von Methoden ermöglichen es, den angezeigten Inhalt beliebig zu verschieben, z. B. ScrollToLeftEnd oder LineRight.
Um die Wirkungsweise der Methoden einfach zu erfahren, dient das folgende Beispielprogramm. Für die in Frage kommenden Methoden sind in der linken Hälfte des Fensters Buttons angeordnet. Die Methode, die von dem jeweiligen Button aufgerufen wird, ist in der Beschriftung angegeben. Der XAML- und C#-Code wird an dieser Stelle aus Platzgründen nur stark gekürzt wiedergegeben.
Abbildung 21.26 Ausgabe des Beispielprogramms »ScrollViewerSample«
// Beispiel: ..\Kapitel 21\ScrollViewerSample
<DockPanel>
<StackPanel DockPanel.Dock="Left" Orientation="Vertical" Width="120"
ButtonBase.Click="ButtonHandler" >
<Button Name="btnLineUp" Margin="5,5,5,5" Content="LineUp()" />
<Button Name="btnLineDown" Margin="5,5,5,5" Content="LineDown()" />
<Button Name="btnLineRight" Margin="5,5,5,5" Content="LineRight()" />
<Button Name="btnLineLeft" Margin="5,5,5,5" Content="LineLeft()" />
[...]
</StackPanel>
<ScrollViewer Name="scrViewer" Margin="5"
HorizontalScrollBarVisibility="Visible"
VerticalScrollBarVisibility="Visible">
<TextBlock Padding="10" TextWrapping="Wrap" Width="500">
[...]
</TextBlock>
</ScrollViewer>
</DockPanel>
Zu diesem XAML-Code gehört der folgende C#-Code:
private void ButtonHandler(object sender, RoutedEventArgs e) {
Button btn = e.Source as Button;
switch (btn.Name) {
case "btnLineUp":
scrViewer.LineUp();
break;
case "btnLineDown":
scrViewer.LineDown();
break;
case "btnLineRight":
scrViewer.LineRight();
break;
[...]
}
}
Listing 21.50 Programmbeispiel »ScrollViewerSample«
21.6.6 Das Steuerelement »Expander«
Das Steuerelement Expander ist der Gruppe der Steuerelemente zuzurechnen, die dem Design dienen. Das Element kann ein untergeordnetes Element beinhalten. Der Bereich, der von dem untergeordneten Steuerelement beschrieben wird, kann aufgeklappt oder zusammengeklappt dargestellt werden. Im zusammengeklappten Zustand wird lediglich ein Pfeil angezeigt, über den der verdeckte Inhalt wieder sichtbar gemacht werden kann. Expander-Objekte eignen sich besonders dann, wenn ein Detailbereich für den Anwender eingeblendet werden soll.
Der Zustand des Expander-Objekts wird mit der Eigenschaft IsExpanded beschrieben. Die Eigenschaft ExpandedDirection gibt die Richtung an, in die aufgeklappt wird. Dabei sind die Richtungen links, rechts, oben und unten möglich. Wird der Inhalt in vertikaler Richtung aufgeklappt, passt sich die Höhe des angezeigten Bereichs dem Inhalt an. Entsprechendes gilt, wenn in horizontaler Richtung aufgeklappt wird. Hier ist es natürlich die Breite, die sich dem Inhalt anpasst.
Erwähnenswert ist, dass beim Öffnen und Schließen des Expander-Objekts die Ereignisse Expanded und Collapsed ausgelöst werden. Sie können somit auf diese Aktionen auch mit entsprechenden Operationen reagieren.
// Beispiel: ..\Kapitel 21\ExpanderSample
<StackPanel>
<Expander Margin="10">
<Expander.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,2">
<GradientStop Offset="0" Color="White" />
<GradientStop Offset="1" Color="Blue" />
</LinearGradientBrush>
</Expander.Background>
<StackPanel>
<Button Height="30" Margin="5">Button 1</Button>
<Button Height="30" Margin="5">Button 2</Button>
<Button Height="30" Margin="5">Button 3</Button>
</StackPanel>
</Expander>
<Expander Margin="10">
<Expander.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,2">
<GradientStop Offset="0" Color="White" />
<GradientStop Offset="1" Color="Red" />
</LinearGradientBrush>
</Expander.Background>
<StackPanel>
<Button Height="30" Margin="5">Button 4</Button>
<Button Height="30" Margin="5">Button 5</Button>
<Button Height="30" Margin="5">Button 6</Button>
</StackPanel>
</Expander>
</StackPanel>
Listing 21.51 Beispiel mit zwei »Expander«-Steuerelementen
Abbildung 21.27 Zwei »Expander«-Objekte (das obere ist zusammengeklappt)
21.6.7 Das Steuerelement »Border«
Das Border-Steuerelement ist ein sehr einfaches Steuerelement, das dazu dient, einen visuellen Rahmen um andere Steuerelemente zu zeichnen. Border ist ein Inhaltssteuerelement. Das bedeutet, dass es direkt nur ein anderes Element beinhalten kann. Üblicherweise handelt es sich dabei um einen Layout-Container.
Nur wenige Eigenschaften sind erwähnenswert: Mit CornerRadius können die Ecken abgerundet werden, BorderThickness legt die Breite fest, und BorderBrush das Aussehen des Rahmens.
<Grid>
<Border CornerRadius="20" BorderThickness="25" Margin="5">
<Border.BorderBrush>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Offset="0" Color="LightGray" />
<GradientStop Offset="1" Color="Black" />
</LinearGradientBrush>
</Border.BorderBrush>
<StackPanel>
<Button Height="40" Margin="20, 20, 20, 10">Button 1</Button>
<Button Height="40" Margin="20, 10, 20, 20">Button 2</Button>
</StackPanel>
</Border>
</Grid>
Listing 21.52 »Border«-Element zur Unterstützung des Designs
Die Ausgabe dieses Beispiels sehen Sie in Abbildung 21.28.
Abbildung 21.28 Ausgabe des Listings 21.52
21.6.8 Die »Image«-Komponente
Mit dem Image-Control lassen sich Grafiken in einem Window anzeigen. Die wichtigste Eigenschaft ist Source, die den relativen oder absoluten Pfad zu einer Grafikdatei beschreibt. Image ermöglicht die Anzeige der folgenden Bildtypen: .BMP, .GIF, .ICO, .JPG, .PNG, .WDP und .TIFF.
Unterscheiden sich die Größe des Image-Controls und die der Grafik, können Sie mit den Eigenschaften Stretch und StretchDirection festlegen, wie die Grafik gestreckt werden soll. StretchDirection erlaubt die Werte Both, DownOnly und UpOnly. Mit DownOnly wird das Bild nur verkleinert dargestellt, mit UpOnly nur vergrößert, und Both ermöglicht beide Änderungen. Letzteres ist auch die Standardvorgabe.
Ist Stretch auf None eingestellt, wird das Bild ausschließlich in seiner Originalgröße dargestellt. Mit Fill wird das Bild so skaliert, dass es den Bereich des Image-Steuerelements komplett einnimmt. UniFormFill agiert ähnlich, achtet aber darauf, dass die Proportionen erhalten bleiben. Leere Flächen innerhalb des Steuerelements verbleiben nicht. Uniform vergrößert oder verkleinert das Bild in der Weise, dass die Proportionen erhalten bleiben. Möglicherweise bleiben dabei aber wieder freie Flächen im Image-Steuerelement.
zeigt, wie sich das Strecken eines Bildes auf die Darstellung auswirkt. Der Abbildung liegt der folgende Code zugrunde:
<WrapPanel>
<Image Source="Images/Seychellen.JPG" Margin="10" Height="200" />
<Image Source="Images/Seychellen.JPG" Margin="10" Height="200"
Width="350" Stretch="Fill" />
</WrapPanel>
Listing 21.53 Bild in richtiger Größe und gestreckt angezeigt
Abbildung 21.29 Bildanzeige »richtig« (links) und gestreckt (rechts)
Grafik zur Laufzeit laden
Wenn Sie mittels Code ein Bitmap laden, kommt die Klasse BitmapImage ins Spiel, die im Namespace System.Windows.Media.Imaging definiert ist. Der Ladevorgang wird zunächst mit der Methode BeginInit initialisiert und mit EndInit abgeschlossen.
Das BitmapImage-Objekt erwartet in der Eigenschaft UriSource die Angabe der Datenquelle, die als Objekt vom Typ Uri übergeben wird. Dem Uri-Konstruktor übergeben Sie den Pfad zu der Bitmap und teilen ihm darüber hinaus mit, ob es sich um eine relative oder absolute Pfadangabe handelt. Der Code in der XAML-Datei lautet:
<WrapPanel>
<Image Name="holidays" />
</WrapPanel>
Das Bild soll beim Starten des Windows geladen werden. Dazu bietet sich das Ereignis Loaded an:
private void Window_Loaded(object sender, RoutedEventArgs e) {
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = new Uri("Images/Egypt.jpg", UriKind.Relative);
bitmap.EndInit();
holidays.Source = bitmap;
}
Listing 21.54 Laden einer Bitmap mit Programmcode
21.6.9 »Calendar« und »DatePicker« zur Datumsangabe
Die Steuerelemente Calendar und DatePicker ermöglichen es dem Anwender, ein Datum auszuwählen. Beide Steuerelemente sind sich sehr ähnlich und unterscheiden sich hauptsächlich durch den beanspruchten Platzbedarf im Fenster. Während das Calendar-Control einen kompletten Monat anzeigt, aus dem der Anwender mit Pfeiltasten einen anderen auswählen kann, erscheint das DatePicker-Steuerelement als eine Art TextBox, in der das Datum angezeigt wird. Das Calendar-Steuerelement wird beim DatePicker erst in dem Moment geöffnet, wenn der Anwender auf die rechts im Steuerelement untergebrachte Schaltfläche klickt.
In Abbildung 21.30 sehen Sie beide Steuerelemente. Das DatePicker ist in der Abbildung zweimal vertreten. Rechts oben ist der eingeklappte Normalzustand zu erkennen, darunter die Situation, wenn der Anwender ein Datum auswählt.
Abbildung 21.30 »Calendar« und »DatePicker«
Hinsichtlich der Eigenschaften gibt es ein paar wenige Unterschiede. Beispielsweise können Sie im DatePicker mit der Eigenschaft SelectedDateFormat das Anzeigeformat Short oder Long auswählen, was dazu führt, dass das Datum entweder in Kurzform (z. B. 16.7.2012) oder im Langformat (z. B. Montag, 16. Juli 2012) angezeigt wird. Im Calendar können Sie mit DisplayMode auch Einfluss auf das Anzeigeformat ausüben. Dabei haben Sie aber die Möglichkeit, zwischen Month, Year und Decade zu entscheiden. Ein paar spezielle Eigenschaften der beiden Steuerelemente sollten wir uns noch in der Tabelle 21.13 ansehen.
Eigenschaft | Beschreibung |
Legt eine Liste von Datumsangaben fest, aus denen nicht ausgewählt werden kann. |
|
Legt das anzuzeigende Datum fest. |
|
Legt das erste bzw. letzte im Kalender verfügbare Datum fest. |
|
Legt fest, ob im Kalender ein Monat, ein Jahr oder ein Jahrzehnt angezeigt werden soll. Diese Eigenschaft hat nur der Typ Calendar. |
|
Legt den Tag fest, der als Wochenanfang gelten soll. |
|
Ruft das aktuell ausgewählte Datum ab oder legt es fest. |
|
Ruft eine Liste ausgewählter Datumsangaben ab. |
|
Diese Eigenschaft ist nur beim Calendar verfügbar. Diese Eigenschaft bestimmt, ob der Calendar keine Auswahl, die Auswahl eines einzelnen Datums oder die Auswahl mehrerer Datumsangaben zulässt. Verfügbare Einstellungen sind None, SingleDate, SingleRange und MultiRange. |
Bei der Wahl eines einzelnen Datums oder eines Bereichs von Datumsangaben wird das Ereignis SelectedDatesChanged ausgelöst. Der zweite Parameter des Ereignishandlers ist vom Typ SelectionChangedEventArgs und liefert in seiner Eigenschaft AddedItems die ausgewählten Datumsangaben in einer Auflistung. Um die gewählten Datumsangaben weiter zu verarbeiten, muss die Liste durchlaufen werden, wie in Listing 21.55 gezeigt wird.
private void Calendar_SelectedDatesChanged(object sender, SelectionChangedEventArgs e)
{
foreach(DateTime date in e.AddedItems) {
if (date.DayOfWeek == DayOfWeek.Sunday)
MessageBox.Show("Diese Auswahl ist leider nicht möglich.");
else
MessageBox.Show("Die Wahl: " + date.ToShortDateString());
}
}
Listing 21.55 Auswerten der Datumswahl
21.6.10 Das Steuerelement »InkCanvas«
Das InkCanvas-Steuerelement ist im Grunde genommen ein Layout-Container, ohne dass es von der Basis Panel abgeleitet wird. Es bietet eine einfache Möglichkeit, Freihandeingaben zu erfassen und anzuzeigen. Freihandeingaben erfolgen im Allgemeinen mit Hilfe eines Tablettstifts, man kann jedoch auch eine Maus anstelle eines Tablettstifts verwenden.
Das InkCanvas birgt in sich zwei Auflistungen. Die erste, Children, gestattet es, ähnlich wie bei dem Canvas, beliebig viele andere Steuerelemente aufzunehmen, die mit den angehängten Eigenschaften Left, Right, Top und Bottom des InkCanvas-Elements absolut positioniert werden.
Die zweite Auflistung, Strokes, enthält die Freihandeingaben des Benutzers, die durch Objekte vom Typ Stroke beschrieben werden. Dabei wird jede Linie oder auch Kurve durch ein Stroke beschrieben. Die wohl wichtigste spezifische Eigenschaft eines InkCanvas-Objekts ist EditingMode. Diese gibt an, wie das Eingabegerät mit dem InkCanvas interagiert. EditingMode ist vom Typ der Enumeration InkCanvasEditingMode und kann die Werte annehmen, die in der folgenden Tabelle 21.14 beschrieben werden.
Wert | Beschreibung |
None |
Es erfolgt keine Aktion. |
Ink |
Freihandeingaben werden auf dem InkCanvas gezeichnet. |
GestureOnly |
Freihandeingaben werden zwar zunächst auf dem InkCanvas dargestellt, aber bei einer Unterbrechung der Datensendung des Eingabegeräts verworfen. In der Dokumentation wird hier auch von »Gesten« gesprochen. |
InkAndGesture |
Das InkCanvas erhält Freihandeingaben und Gesten. |
Select |
Ermöglicht das Auswählen von Strichen und sogar Elementen, die sich im InkCanvas befinden. |
EraseByPoint |
Löscht den Teil des Striches, auf den das Eingabegerät zeigt. |
EraseByStroke |
Löscht den gesamten Strich, auf den das Eingabegerät zeigt. |
Wir sollten uns nun das Steuerelement InkCanvas an einem konkreten Beispiel ansehen. Nach dem Start der Anwendung wird das Fenster wie in Abbildung 21.31 gezeigt dargestellt.
Abbildung 21.31 Anwendung mit »InkCanvas« nach dem Starten
Der Code, der der Abbildung zugrunde liegt, ist der folgende.
// Beispiel: ..\Kapitel 21\InkCanvasSample
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<StackPanel Margin="5" Orientation="Horizontal">
<TextBlock Margin="5">Modus:</TextBlock>
<ComboBox Name="cboBox" Width="120" VerticalAlignment="Center" />
</StackPanel>
<InkCanvas Name="inkCanvas" Grid.Row="1" Margin="10" Background="LightGray"
EditingMode="{Binding ElementName=cboBox,Path=SelectedItem}" >
<StackPanel InkCanvas.Top="10" InkCanvas.Left="350">
<Button Margin="10" Width="100">Testschaltfläche 1</Button>
<Button Width="100">Testschaltfläche 2</Button>
</StackPanel>
<Image Source="Koala.jpg" InkCanvas.Top="10" InkCanvas.Left="10"
Width="230" Height="172" />
</InkCanvas>
</Grid>
Dazu gehört auch noch der folgende C#-Code, um das Kombinationslistenfeld mit den Konstanten aus der Enumeration InkCanvasEditingMode zu füllen.
public MainWindow() {
InitializeComponent();
foreach (InkCanvasEditingMode mode
in Enum.GetValues(typeof(InkCanvasEditingMode))) {
cboBox.Items.Add(mode);
cboBox.SelectedItem = inkCanvas.EditingMode;
}
}
Listing 21.56 Beispielprogramm zur Demonstration des »InkCanvas«-Controls
Abbildung 21.32 Änderungen am »InkCanvas« zur Laufzeit
Probieren Sie die verschiedenen Editiermodi einmal aus. Das Ergebnis könnte etwa wie in Abbildung 21.32 aussehen.
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.