資源下載連接
https://download.csdn.net/download/sinat_30224769/12362527
獲取背景板
public VisualBrush GetVisualBrush()
{
VisualBrush brush = new VisualBrush();
brush.Stretch = Stretch.Fill;
brush.Visual = myViewbox;
brush.Opacity = 0.75;
return brush;
}
ZoomBox.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ZoomBox
{
/// <summary>
/// Interaction logic for ZoomBoxControl.xaml
/// </summary>
public partial class ZoomBoxControl : UserControl
{
public ZoomBoxControl()
{
InitializeComponent();
}
public enum Orientation
{
Horizontal,
Vertical
}
public class ZoomArea
{
public Size ScreenSize { get; set; }
/// <summary>
/// 畫布大小 這裏目前展示的是最大節點位置的大小
/// </summary>
public Size CanvasSize { get; set; }
//public Size ViewSize { get; set; }
}
/// <summary>
/// 通知界面刷新
/// </summary>
public event Action<Orientation, double> OffsetChangedEventHandel;
/// <summary>
/// 獲取縮略圖背景
/// </summary>
public event Func<VisualBrush> GetCanvasBrushEventHandel;
/// <summary>
/// 獲取縮略圖範圍
/// </summary>
public event Func<ZoomArea> GetNodeMaxAreaEventHandel;
/// <summary>
/// 保留尺寸方便調用
/// </summary>
public Size MainCanvasSize
{
get { return (Size)GetValue(MainCanvasSizeProperty); }
set { SetValue(MainCanvasSizeProperty, value); }
}
// Using a DependencyProperty as the backing store for MainCanvasSize. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MainCanvasSizeProperty =
DependencyProperty.Register("MainCanvasSize", typeof(Size), typeof(ZoomBoxControl), new PropertyMetadata(new Size(200, 100)));
public bool IsExpanded
{
get { return (bool)GetValue(IsExpandedProperty); }
set { SetValue(IsExpandedProperty, value); }
}
// Using a DependencyProperty as the backing store for IsExpanded. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsExpandedProperty =
DependencyProperty.Register("IsExpanded", typeof(bool), typeof(ZoomBoxControl), new PropertyMetadata(false));
/// <summary>
/// 更新縮略圖範圍
/// </summary>
/// <param name="zoomArea"></param>
public void UpdateBackground(ZoomArea zoomArea)
{
if (zoomArea == null)
{
return;
}
//那一邊長哪一邊就直接展示200的長度
double max = System.Math.Max(zoomArea.CanvasSize.Width, zoomArea.CanvasSize.Height);
double min = System.Math.Min(zoomArea.CanvasSize.Width, zoomArea.CanvasSize.Height);
double rate = max / min;
if (rate >= 4)
{
zoomArea.CanvasSize = new Size(max, max);
}
this.MainCanvasSize = zoomArea.CanvasSize;
if (zoomArea.CanvasSize.Width > zoomArea.CanvasSize.Height)
{
rate = this.MainCanvasSize.Height / this.MainCanvasSize.Width;
ZoomBoxCanvas.Width = this.Width;
ZoomBoxCanvas.Height = this.Width * rate;
ZoomBackground.Height = ZoomBoxCanvas.Height;
ZoomBackground.Width = ZoomBoxCanvas.Width;
}
else
{
rate = this.MainCanvasSize.Width / this.MainCanvasSize.Height;
ZoomBoxCanvas.Height = this.Height;
ZoomBoxCanvas.Width = this.Height * rate;
ZoomBackground.Height = ZoomBoxCanvas.Height;
ZoomBackground.Width = ZoomBoxCanvas.Width;
}
double scRateWidth = zoomArea.ScreenSize.Width / zoomArea.CanvasSize.Width;
double scRateHeight = zoomArea.ScreenSize.Height / zoomArea.CanvasSize.Height;
if (scRateWidth >= 1)
{
//說明屏幕展示的下 那麼在水平方向上 滑塊不可移動 應該等於畫布大小
ZoomThumb.Width = ZoomBoxCanvas.Width;
}
else
{
var newWidth = scRateWidth * ZoomBoxCanvas.Width;
if (newWidth < 40)
{
newWidth = 40;
}
ZoomThumb.Width = newWidth;
}
if (scRateHeight >= 1)
{
//說明屏幕展示的下 那麼在垂直方向上 滑塊不可移動 應該等於畫布大小
ZoomThumb.Height = ZoomBoxCanvas.Height;
}
else
{
var newHeight = scRateHeight * ZoomBoxCanvas.Height;
if (newHeight < 40)
{
newHeight = 40;
}
ZoomThumb.Height = newHeight;
}
}
/// <summary>
/// 更新滑塊位置
/// </summary>
/// <param name="offsetX"></param>
/// <param name="offsetY"></param>
public void ScrollChanged(double offsetX, double offsetY)
{
double offsetRateX = this.MainCanvasSize.Width / (this.ZoomBoxCanvas.Width - this.ZoomThumb.Width);
double offsetRateY = this.MainCanvasSize.Height / (this.ZoomBoxCanvas.Height - this.ZoomThumb.Height);
Canvas.SetLeft(ZoomThumb, offsetX / offsetRateX);
Canvas.SetTop(ZoomThumb, offsetY / offsetRateY);
}
/// <summary>
/// 拖拽滑塊
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ZoomThumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
{
//var ZoomThumb = sender as Thumb;
Point ptChange = ZoomThumb.RenderTransform.Transform(new Point(e.HorizontalChange, e.VerticalChange));
double left = Canvas.GetLeft(ZoomThumb);
double top = Canvas.GetTop(ZoomThumb);
double offsetX = 0;
double offsetY = 0;
double offsetRateX = this.MainCanvasSize.Width / (this.ZoomBoxCanvas.Width - this.ZoomThumb.Width);
double offsetRateY = this.MainCanvasSize.Height / (this.ZoomBoxCanvas.Height - this.ZoomThumb.Height);
double minLeft = 0;
double maxLeft = this.ZoomBoxCanvas.Width - ZoomThumb.Width;
double minTop = 0;
double maxTop = this.ZoomBoxCanvas.Height - ZoomThumb.Height;
Console.WriteLine(left + "," + top + "," + e.HorizontalChange + "," + e.VerticalChange);
if (e.HorizontalChange <= 0)
{
if (left <= minLeft)
{
offsetX = minLeft;
}
else
{
offsetX = left + ptChange.X;
}
}
else if (e.HorizontalChange >= 0)
{
if (left >= maxLeft)
{
offsetX = maxLeft;
}
else
{
offsetX = left + ptChange.X;
}
}
else
{
offsetX = left + ptChange.X;
}
Canvas.SetLeft(ZoomThumb, offsetX);
//scroll.ScrollToHorizontalOffset(offsetX * offsetRate);
OffsetChangedEventHandel?.Invoke(Orientation.Horizontal, offsetX * offsetRateX);
if (e.VerticalChange <= 0)
{
if (top <= minTop)
{
offsetY = minTop;
}
else
{
offsetY = top + ptChange.Y;
}
}
else if (e.VerticalChange >= 0)
{
if (top >= maxTop)
{
offsetY = maxTop;
}
else
{
offsetY = top + ptChange.Y;
}
}
else
{
offsetY = top + ptChange.Y;
}
Canvas.SetTop(ZoomThumb, offsetY);
//scroll.ScrollToVerticalOffset(offsetY * offsetRate);
OffsetChangedEventHandel?.Invoke(Orientation.Vertical, offsetY * offsetRateY);
//Console.WriteLine($"left:{scroll.ContentHorizontalOffset} top:{scroll.ContentVerticalOffset} OffsetX:{scroll.HorizontalOffset} OffsetY:{scroll.VerticalOffset}");
}
private void Expand_Click(object sender, RoutedEventArgs e)
{
IsExpanded = !IsExpanded;
if (IsExpanded && GetNodeMaxAreaEventHandel != null)
{
var zoomSize = GetNodeMaxAreaEventHandel.Invoke();
UpdateBackground(zoomSize);
this.Dispatcher.InvokeAsync(() =>
{
ZoomBackground.Background = GetCanvasBrushEventHandel?.Invoke();
});
}
}
//調用的位置 在滾動條變動的時候要發起通知
//private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
//{
// var xx = scroll;
// Console.WriteLine($"left:{scroll.ContentHorizontalOffset} top:{scroll.ContentVerticalOffset} OffsetX:{scroll.HorizontalOffset} OffsetY:{scroll.VerticalOffset}");
//}
}
}
ZoomBox.xml
<UserControl x:Class="ZoomBox.ZoomBoxControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ZoomBox"
mc:Ignorable="d" x:Name="uc"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<SolidColorBrush x:Key="ThemColour" Color="LightGreen"/>
<local:BooleanToVisibility x:Key="BooleanToVisibility" />
<local:BooleanToReverseVisibility x:Key="BooleanToReverseVisibility" />
</UserControl.Resources>
<Grid>
<Grid Background="#4CFFFFFF" Visibility="{Binding IsExpanded,ElementName=uc,Converter={StaticResource BooleanToVisibility}}">
<Border BorderThickness="1" BorderBrush="{StaticResource ThemColour}" d:IsHidden="True"/>
<!--<Border BorderThickness="1" BorderBrush="#FFFBA90D" d:IsHidden="True"/>-->
<Canvas Name="ZoomBoxCanvas" Width="800" Height="100">
<!--<Image Opacity="1" x:Name="ZoomBackground" Stretch="UniformToFill" Width="{Binding Width,ElementName=ZoomBoxCanvas}" Height="{Binding Height,ElementName=ZoomBoxCanvas}"/>-->
<Border BorderThickness="1" BorderBrush="{StaticResource ThemColour}" Width="{Binding Width,ElementName=ZoomBoxCanvas}" Height="{Binding Height,ElementName=ZoomBoxCanvas}"/>
<Grid x:Name="ZoomBackground" />
<Grid x:Name="ZoomThumb" Canvas.Left="0" Canvas.Top="0" Height="38" Width="50" Background="{StaticResource ThemColour}" >
<Thumb Opacity="0.1" Background="Transparent" DragDelta="ZoomThumb_DragDelta" HorizontalAlignment="Left" Height="{Binding Height,ElementName=ZoomThumb}" Width="{Binding Width,ElementName=ZoomThumb}" VerticalAlignment="Top" Foreground="{x:Null}" BorderBrush="Black"/>
</Grid>
</Canvas>
</Grid>
<RadioButton Click="Expand_Click" Visibility="{Binding IsExpanded,ElementName=uc,Converter={StaticResource BooleanToReverseVisibility }}" HorizontalAlignment="Right" Height="56" Width="22" Margin="0" VerticalAlignment="Bottom">
<RadioButton.Template>
<ControlTemplate>
<Grid Background="White">
<Border BorderThickness="1" BorderBrush="{StaticResource ThemColour}"/>
<TextBlock Text="縮略圖" Foreground="{StaticResource ThemColour}" VerticalAlignment="Center" HorizontalAlignment="Center" TextWrapping="Wrap" FontSize="14"/>
</Grid>
</ControlTemplate>
</RadioButton.Template>
</RadioButton>
<RadioButton Click="Expand_Click" Visibility="{Binding IsExpanded,ElementName=uc,Converter={StaticResource BooleanToVisibility}}" HorizontalAlignment="Right" Height="22" Width="22" Margin="0" VerticalAlignment="Bottom" MinHeight="0">
<RadioButton.Template>
<ControlTemplate>
<Grid Background="White">
<Border BorderThickness="1" BorderBrush="{StaticResource ThemColour}"/>
<TextBlock Text=">>" Foreground="{StaticResource ThemColour}" VerticalAlignment="Center" HorizontalAlignment="Center" TextWrapping="Wrap" FontSize="14"/>
</Grid>
</ControlTemplate>
</RadioButton.Template>
</RadioButton>
</Grid>
</UserControl>
Main.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ZoomBox
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
zoomBox.ScrollChanged(scrollViewer.HorizontalOffset, scrollViewer.VerticalOffset);
}
private void ZoomBoxControl_OffsetChangedEventHandel(ZoomBoxControl.Orientation arg1, double arg2)
{
if (double.IsNaN(arg2))
{
return;
}
if (arg1 == ZoomBoxControl.Orientation.Horizontal)
{
scrollViewer.ScrollToHorizontalOffset(arg2);
}
else
{
scrollViewer.ScrollToVerticalOffset(arg2);
}
}
private ZoomBoxControl.ZoomArea zoomBox_GetNodeMaxAreaEventHandel()
{
ZoomBoxControl.ZoomArea zoomArea = new ZoomBoxControl.ZoomArea();
zoomArea.ScreenSize = scrollViewer.RenderSize;
zoomArea.CanvasSize = VeryBigCanvas.RenderSize;
return zoomArea;
}
private VisualBrush zoomBox_GetCanvasBrushEventHandel()
{
return GetVisualBrush();
}
public VisualBrush GetVisualBrush()
{
VisualBrush brush = new VisualBrush();
brush.Stretch = Stretch.Fill;
brush.Visual = VeryBigCanvas;
brush.Opacity = 0.75;
return brush;
}
}
}
Main.xml
<Window x:Class="ZoomBox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ZoomBox"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<ScrollViewer x:Name="scrollViewer" ScrollChanged="ScrollViewer_ScrollChanged" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Canvas x:Name="VeryBigCanvas" HorizontalAlignment="Left" Height="4320" Width="7680" VerticalAlignment="Top" >
<Canvas.Background>
<ImageBrush ImageSource="lol娑娜大胸白絲4k壁紙_彼岸圖網.jpg"/>
</Canvas.Background>
</Canvas>
</ScrollViewer>
<local:ZoomBoxControl x:Name="zoomBox" OffsetChangedEventHandel="ZoomBoxControl_OffsetChangedEventHandel" GetNodeMaxAreaEventHandel="zoomBox_GetNodeMaxAreaEventHandel" GetCanvasBrushEventHandel="zoomBox_GetCanvasBrushEventHandel" Width="200" Height="200" Margin="0,0,20,20" VerticalAlignment="Bottom" HorizontalAlignment="Right" />
</Grid>
</Window>