WPF 可缩放ScrollView(方式二)
增加了缩放Maximun、Minimun和Value值,以及可供监听缩放变化的ValueChanged事件。
public class ScaleScrollView : ScrollViewer
{
readonly List<object> ValueChangedEvents = new List<object>();
public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent("ValueChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<double>), typeof(ScaleScrollView));
/// <summary>
/// 通过监听此事件对内容进行缩放
/// </summary>
public event RoutedPropertyChangedEventHandler<double> ValueChanged
{
add => AddHandler(ValueChangedEvent, value);
remove => RemoveHandler(ValueChangedEvent, value);
}
#region Properties
public double Maximum
{
get { return (double)GetValue(MaximumProperty); }
set { SetValue(MaximumProperty, value); }
}
public static readonly DependencyProperty MaximumProperty =
DependencyProperty.Register("Maximum", typeof(double), typeof(ScaleScrollView), new PropertyMetadata(1200d));
public double Minimum
{
get { return (double)GetValue(MinimumProperty); }
set { SetValue(MinimumProperty, value); }
}
public static readonly DependencyProperty MinimumProperty =
DependencyProperty.Register("Minimum", typeof(double), typeof(ScaleScrollView), new PropertyMetadata(1d));
public double SmallChange
{
get { return (double)GetValue(SmallChangeProperty); }
set { SetValue(SmallChangeProperty, value); }
}
// Using a DependencyProperty as the backing store for SmallChange. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SmallChangeProperty =
DependencyProperty.Register("SmallChange", typeof(double), typeof(ScaleScrollView), new PropertyMetadata(1d));
public double Value
{
get { return (double)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(double), typeof(ScaleScrollView),
new FrameworkPropertyMetadata(100d, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange, propertyChangedCallback: onValueConagend));
private static void onValueConagend(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ScaleScrollView view = d as ScaleScrollView;
int ov = Convert.ToInt32(e.OldValue);
int nv = Convert.ToInt32(e.NewValue);
RoutedPropertyChangedEventArgs<double> args = new RoutedPropertyChangedEventArgs<double>(ov, nv);
args.RoutedEvent = ValueChangedEvent;
view.RaiseEvent(args);
if (args.Handled) return;
if (view.Content is FrameworkElement element)
{
double w = element.ActualWidth + element.ActualWidth * (nv - ov) / 100;
element.Width = w < 1.0 ? 1.0 : w;
double h = element.ActualHeight + element.ActualHeight * (nv - ov) / 100;
element.Height = h < 1.0 ? 1.0 : h;
}
}
#endregion
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
if (e.Handled) { return; }
if (ScrollInfo != null)
{
//Shift+滚动:上下滚动
//Ctrl+滚动:左右滚动
//滚动:放大缩小
if (Keyboard.IsKeyDown(Key.LeftShift))
{
if (e.Delta > 0)
ScrollInfo.MouseWheelUp();
else
ScrollInfo.MouseWheelDown();
}
else if (Keyboard.IsKeyDown(Key.LeftCtrl))
{
if (e.Delta > 0)
ScrollInfo.LineLeft();
else
ScrollInfo.MouseWheelRight();
}
else
{
Value += e.Delta > 0 ? SmallChange : -SmallChange;
}
}
e.Handled = true;
}
}
示例:
<DockPanel>
<WrapPanel DockPanel.Dock="Bottom">
<Slider Name="sliderScale" Minimum="1" Value="100" Maximum="1000" SmallChange="1" LargeChange="50" IsSnapToTickEnabled="True" Width="100"/>
<TextBlock Text="{Binding ElementName=sliderScale, Path=Value}" VerticalAlignment="Center"/>
</WrapPanel>
<controls:ScaleScrollView HorizontalScrollBarVisibility="Visible" Value="{Binding ElementName=sliderScale, Path=Value, Mode=TwoWay}">
<Viewbox Name="viewbox">
<Border Width="2000" Height="2000" Background="Orange">
<Canvas>
<Rectangle Fill="Red" Width="1000" Height="1000"/>
</Canvas>
</Border>
</Viewbox>
</controls:ScaleScrollView>
</DockPanel>