In my WPF application (created using C# and Visual Studio), I have an ItemsControl; the items are instances of a custom class, Line. The Line class contains the x and y coordinates of the line:
public class Line{
private double _x1, _y1, _x2, _y2;
public double X1{
get{ return _x1; }
set{ _x1 = value; }
}
public double Y1{
get{ return _y1; }
set{ _y1 = value; }
}
public double X2{
get{ return _x2; }
set{ _x2 = value; }
}
public double Y2{
get{ return _y2; }
set{ _y2 = value; }
}
}
The line representing a Line instance is bound (using Data Binding) to these start and end points.
In another part of the window there is a Slider which should represent the scale value of the application. Now I want the behaviour so that when I drag the scale Slider, the lines should scale according to the Slider's value. How can I achieve this?
I tried to change the getter methods like this one:
public double X1{
get{ return _x1*scale; }
set{ _x1 = value; }
}
But then I have 2 problems: 1) Where do I get the "scale" value from? The Line class does not know about the MainWindow or the Slider. 2) I managed to get the "scale" value from the Slider using a bad programming style (using a static public "currentSlider" property) like here:
public class MainWindow{
public static Slider currentSlider;
public MainWindow(){
InitializeComponents();
currentSlider = slider1;
}
}
Then the Line class can access the scale value and new lines are created using the right scale factor. But when I move the Slider, the lines do not get updated and scaled.
So how can I make the lines scale according to the value of the Slider?
The question suggests that you want to scale the start and end points of the Line, but not the rendered stroke thickness. Hence you can't simply apply a transform to the LayoutTransform
or RenderTransform
property of the Line in the DataTemplate.
An alternative would be to use a Path with a LineGeometry. As the LineGeometry has a StartPoint
and an EndPoint
property instead of the X1
, Y1
, X2
and Y2
of the Line class, you would however either use a binding converter, or change your item class into something like this:
public class Line
{
public Point P1 { get; set; }
public Point P2 { get; set; }
}
In your ItemsControl you would now bind the LineGeometry's StartPoint
and EndPoint
properties, and put a ScaleTransform into the LineGeometry's Transform
. The ScaleTransform has the ScaleX
and ScaleY
properties, which would be bound to the Slider's Value
.
<ItemsControl ItemsSource="{Binding Lines}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Path Stroke="Black" StrokeThickness="1">
<Path.Data>
<LineGeometry StartPoint="{Binding P1}" EndPoint="{Binding P2}">
<LineGeometry.Transform>
<ScaleTransform
ScaleX="{Binding Value, ElementName=slider}"
ScaleY="{Binding Value, ElementName=slider}"/>
</LineGeometry.Transform>
</LineGeometry>
</Path.Data>
</Path>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
...
<Slider x:Name="slider" Width="200" Minimum="1" Maximum="10"/>