Kürzlich stand ich vor folgendem Problem: Gegeben ist ein ScrollViewer, darin enthalten ein Canvas. Auf letzterem Element werden andere Elemente platziert, die auch entsprechend verschoben werden können, wodurch eine Scroll-Funktionalität gegeben sein sollte. Nun mussten diese Elemente zoombar sein.
Bevor wir uns dem Sourcecode zuwenden, hier kurz das eigentliche Problem: Die Zoomfunktionalität wurde mittels ScaleTransform und RenderTransform (für den Typ UIElement verfügbar) umgesetzt. Im ersten Moment war jedoch verwunderlich, dass der ScrollViewer nicht ansprang und somit trotz vergrößerter Darstellung kein scrollen möglich war.
Nun ist es so, dass Objekte vom Typ FrameworkElement eine Methode LayoutTransform aufweisen, welche nicht nur auf das tatsächliche Element, sondern auf das gesamte Layout Auswirkung hat. Dies hat nun zur Folge, dass bei Verwendung von LayoutTransform der ScrollViewer anspringt und das gewünschte Ergebnis bringt, hingegen die Methode RenderTransform zwar die Elemente transformiert, jedoch das Layout davon unberührt läßt.
Hier nun das XAML eines Beispiels mit dem darauffolgenden Screenshot, damit man sich darunter auch etwas vorstellen kann:
Die nachfolgende Methode ist zuständig, um die tatsächliche Auswahl des Zoomfaktors auf den Canvas anzuwenden, d.h. der gesamte Canvas inkl. der Inhalte wird vergrößert. Zu beachten ist, dass durch diese Transformation die Veränderung der Größe nur temporär ist.
privatevoid Zoom(double zoomfactor)
{
ScaleTransform st = new ScaleTransform(zoomfactor, zoomfactor);
if (TransformType.Text == "RenderTransform")
ButtonCanvas.RenderTransform = st;
else
ButtonCanvas.LayoutTransform = st;
}
Hier ist ebenfalls zu sehen, dass auch die zweite ComboBox ausgewertet wird, damit auch der Unterschied ersichtlich ist.
Das Ergebnis mittels RenderTransform:
Das Ergebnis mittels LayoutTransform:
Damit das auch jeder ausprobieren kann, hier noch der gesamte Codebehind-Code:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;
namespace WpfZoomDemo
{
publicpartialclass Window1 : Window
{
public Window1()
{
InitializeComponent();
List<int> listToBind = new List<int>();
listToBind.Add(25);
listToBind.Add(50);
listToBind.Add(75);
listToBind.Add(100);
listToBind.Add(125);
listToBind.Add(150);
listToBind.Add(200);
listToBind.Add(300);
BindToComboBox(
listToBind,
this.ZoomComboBox);
this.ZoomComboBox.SelectionChanged +=
new SelectionChangedEventHandler
(ZoomComboBox_SelectionChanged);
}
void ZoomComboBox_SelectionChanged(
object sender,
SelectionChangedEventArgs e)
{
IList selItems = e.AddedItems;
if (selItems.Count > 0)
{
string selItem = selItems[0].ToString();
int iZoomVal = 100;
Int32.TryParse(selItem.Replace("%",""),
out iZoomVal);
Zoom((double)iZoomVal/100);
}
}
privatevoid BindToComboBox(
List<int> listToBind,
ComboBox cBox)
{
if (!listToBind.Contains(100))
listToBind.Add(100);
listToBind.Sort();
List<string> tempList = new List<string>();
listToBind.ForEach(delegate(int itemValue) {
if (!itemValue.ToString().Trim().EndsWith("%"))
tempList.Add(itemValue.ToString().Trim() + "%");
else
tempList.Add(itemValue.ToString());
});
Binding b = new Binding();
b.Source = tempList;
cBox.SetBinding(ComboBox.ItemsSourceProperty, b);
cBox.SelectedValue = "100%";
}
privatevoid Zoom(double zoomfactor)
{
ScaleTransform st =
new ScaleTransform(zoomfactor, zoomfactor);
if (TransformType.Text == "RenderTransform")
ButtonCanvas.RenderTransform = st;
else
ButtonCanvas.LayoutTransform = st;
}
}
}
Wer also derartige Transformierungen durchführen möchte, der sollte sich durchaus überlegen, was davon alles betroffen sein soll. Auf dieser Basis sollte dann zwischen RenderTransform und LayoutTransform gewählt werden.