You can make a class that calculates the scale and passes it to the ViewModel.
An approximate implementation and its use.You can make a class that calculates the scale and passes it to the ViewModel.
An approximate implementation and its use.
public class ScaleCalcBinding : Freezable
{
public FrameworkElement SourceElement
{
get { return (FrameworkElement)GetValue(SourceElementProperty); }
set { SetValue(SourceElementProperty, value); }
}
// Using a DependencyProperty as the backing store for SourceElement. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SourceElementProperty =
DependencyProperty.Register(nameof(SourceElement), typeof(FrameworkElement), typeof(ScaleCalcBinding), new PropertyMetadata(null, ElementChanged));
private static void ElementChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ScaleCalcBinding dd = (ScaleCalcBinding)d;
FrameworkElement element = e.OldValue as FrameworkElement;
if (element != null)
element.SizeChanged -= dd.CalcScale;
element = e.NewValue as FrameworkElement;
if (element != null)
element.SizeChanged += dd.CalcScale;
dd.CalcScale();
}
private void CalcScale(object sender = null, SizeChangedEventArgs e = null)
{
if (SourceElement == null || TargetElement == null || ScanScale == null)
{
ScaleWidthResult = null;
ScaleHeightResult = null;
return;
}
ScaleWidthResult = SourceElement.ActualWidth / TargetElement.ActualWidth * ScanScale.Value;
ScaleHeightResult = SourceElement.ActualHeight / TargetElement.ActualHeight * ScanScale.Value;
}
public FrameworkElement TargetElement
{
get { return (FrameworkElement)GetValue(TargetElementProperty); }
set { SetValue(TargetElementProperty, value); }
}
// Using a DependencyProperty as the backing store for TargetElement. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TargetElementProperty =
DependencyProperty.Register(nameof(TargetElement), typeof(FrameworkElement), typeof(ScaleCalcBinding), new PropertyMetadata(null));
public double? ScanScale
{
get { return (double?)GetValue(ScanScaleProperty); }
set { SetValue(ScanScaleProperty, value); }
}
// Using a DependencyProperty as the backing store for ScanScale. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ScanScaleProperty =
DependencyProperty.Register(nameof(ScanScale), typeof(double?), typeof(ScaleCalcBinding), new PropertyMetadata(null, ElementChanged));
public double? ScaleWidthResult
{
get { return (double?)GetValue(ScaleResultWidthProperty); }
set { SetValue(ScaleResultWidthProperty, value); }
}
// Using a DependencyProperty as the backing store for ScaleWidthResult. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ScaleResultWidthProperty =
DependencyProperty.Register(nameof(ScaleWidthResult), typeof(double?), typeof(ScaleCalcBinding), new PropertyMetadata(null));
public double? ScaleHeightResult
{
get { return (double?)GetValue(ScaleHeightResultProperty); }
set { SetValue(ScaleHeightResultProperty, value); }
}
// Using a DependencyProperty as the backing store for ScaleHeightResult. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ScaleHeightResultProperty =
DependencyProperty.Register(nameof(ScaleHeightResult), typeof(double?), typeof(ScaleCalcBinding), new PropertyMetadata(null));
protected override Freezable CreateInstanceCore() => new ScaleCalcBinding();
}
XAML
<Window
x:Name="window"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:CF2002"
x:Class="CF2002.MainWindow"
Title="MainWindow"
mc:Ignorable="d"
WindowStartupLocation="CenterScreen"
Foreground="White"
Background="#FF79C2FF"
Height="300" Width="300"
FontSize="14">
<Window.Resources>
<local:ViewModelScale x:Key="viewModel"/>
<local:ScaleCalcBinding
x:Key="ScaleCalc"
ScaleHeightResult="{Binding ScaleHeight, Mode=OneWayToSource}"
ScaleWidthResult="{Binding ScaleWidth, Mode=OneWayToSource}"
ScanScale="{Binding Text, ElementName=textBox}"
SourceElement="{Binding ElementName=grid, Mode=OneWay}"
TargetElement="{Binding ElementName=border, Mode=OneWay}"
/>
</Window.Resources>
<Window.DataContext>
<Binding Mode="OneWay" Source="{StaticResource viewModel}"/>
</Window.DataContext>
<Grid x:Name="grid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock HorizontalAlignment="Left" />
<TextBlock HorizontalAlignment="Right" />
<TextBox x:Name="textBox" TextAlignment="Center"
Background="Transparent"
Text="5"/>
<Grid Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border x:Name="border" Background="LightGreen">
<StackPanel>
<TextBlock >
<Run Text="{Binding ActualWidth, ElementName=grid, Mode=OneWay}"/>
<Run Text=", "/>
<Run Text="{Binding ActualHeight, ElementName=grid, Mode=OneWay}"/>
</TextBlock>
<TextBlock >
<Run Text="{Binding ActualWidth, ElementName=border, Mode=OneWay}"/>
<Run Text=", "/>
<Run Text="{Binding ActualHeight, ElementName=border, Mode=OneWay}"/>
</TextBlock>
<TextBlock >
<Run Text="{Binding ScaleWidth}"/>
<Run Text=", "/>
<Run Text="{Binding ScaleHeight}"/>
</TextBlock>
</StackPanel>
</Border>
<GridSplitter Grid.Column="1" ShowsPreview="False" Width="3" Grid.RowSpan="3"
HorizontalAlignment="Center" VerticalAlignment="Stretch" />
<GridSplitter Grid.Row="1" ShowsPreview="False" Height="3" Grid.ColumnSpan="3"
VerticalAlignment="Center" HorizontalAlignment="Stretch" Tag="{Binding Mode=OneWay, Source={StaticResource ScaleCalc}}"/>
</Grid>
</Grid>
</Window>
ViewModel
public class ViewModelScale
{
private double _scaleWidth;
private double _scaleHeight;
// In property setters, recalculate coordinate values from the source collection to the collection for display.
public double ScaleWidth { get => _scaleWidth; set { _scaleWidth = value; RenderScale(); } }
public double ScaleHeight { get => _scaleHeight; set { _scaleHeight = value; RenderScale(); } }
public ObservableCollection<CustomType> ViewCollection { get; } = new ObservableCollection<CustomType>();
public ObservableCollection<CustomType> SourceCollection { get; } = new ObservableCollection<CustomType>();
private void RenderScale()
{
for (int i = 0; i < ViewCollection.Count; i++)
{
ViewCollection[i].X = SourceCollection[i].X * ScaleWidth;
ViewCollection[i].Y = SourceCollection[i].Y * ScaleHeight;
}
}
}