惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
The Exploit Database - CXSecurity.com
F
Fortinet All Blogs
U
Unit 42
F
Full Disclosure
雷峰网
雷峰网
博客园 - 司徒正美
云风的 BLOG
云风的 BLOG
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Tailwind CSS Blog
The Cloudflare Blog
Last Week in AI
Last Week in AI
罗磊的独立博客
D
DataBreaches.Net
C
Check Point Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
O
OpenAI News
C
CXSECURITY Database RSS Feed - CXSecurity.com
aimingoo的专栏
aimingoo的专栏
S
Security @ Cisco Blogs
大猫的无限游戏
大猫的无限游戏
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
S
SegmentFault 最新的问题
NISL@THU
NISL@THU
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Hacker News
The Hacker News
Webroot Blog
Webroot Blog
Security Latest
Security Latest
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Google DeepMind News
Google DeepMind News
酷 壳 – CoolShell
酷 壳 – CoolShell
N
News | PayPal Newsroom
P
Proofpoint News Feed
B
Blog RSS Feed
MongoDB | Blog
MongoDB | Blog
C
Cybersecurity and Infrastructure Security Agency CISA
N
News and Events Feed by Topic
Google Online Security Blog
Google Online Security Blog
H
Help Net Security
Spread Privacy
Spread Privacy
T
Threat Research - Cisco Blogs
GbyAI
GbyAI
I
Intezer
Application and Cybersecurity Blog
Application and Cybersecurity Blog
M
MIT News - Artificial intelligence
Vercel News
Vercel News
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
IT之家
IT之家
MyScale Blog
MyScale Blog
腾讯CDC

博客园 - HotSky

Chrome启用CDP(chrome-devtools-protocol)进行远程操控 WPF 让ScrollViewer支持按住鼠标中键拖拽滚动内容 Nodejs使用 nodejs中写sql需要用in时的写法 C#城市最短路径 C#Animation Sqlite PDF附录A: 内容流操作码 WPF FPS类 生命模拟 C# Sql帮助类,可扩展 WPF WriteableBitmap通过GDI+绘制帮助类 Alpha混合 Bmp读写二值图 WPF支持任意快捷键+鼠标组合的绑定类 WPF阻止窗体被系统缩放,使用显示器DPI WPF DataGrid自动增长序号列 C#访问或修改私有类、函数、变量、属性 WPF一个简单的属性编辑控件
WPF 让ScrollViewer支持鼠标中键滚动缩放内容
HotSky · 2026-01-27 · via 博客园 - HotSky
public class ScrollViewerMouseWheelScaleBehavior : Behavior<ScrollViewer>
{
    public static readonly DependencyProperty MaxScaleProperty = DependencyProperty.Register("MaxScale", typeof(double), typeof(ScrollViewerMouseWheelScaleBehavior), new PropertyMetadata(10.0));
    public static readonly DependencyProperty MinScaleProperty = DependencyProperty.Register("MinScale", typeof(double), typeof(ScrollViewerMouseWheelScaleBehavior), new PropertyMetadata(0.1d));
    public static readonly DependencyProperty ScaleProperty = DependencyProperty.Register("Scale", typeof(double), typeof(ScrollViewerMouseWheelScaleBehavior), new FrameworkPropertyMetadata(1.0));
    
    public double MaxScale
    {
        get { return (double)GetValue(MaxScaleProperty); }
        set { SetValue(MaxScaleProperty, value); }
    }

    public double MinScale
    {
        get { return (double)GetValue(MinScaleProperty); }
        set { SetValue(MinScaleProperty, value); }
    }

    public double Scale
    {
        get { return (double)GetValue(ScaleProperty); }
        set { SetValue(ScaleProperty, value); }
    }


    public EventHandler<ScaleChangedEventArgs> ScaleChanged { get; set; }

    ScrollViewer scrollviewer;
    FrameworkElement Content;

    public ScrollViewerMouseWheelScaleBehavior() { }
    public ScrollViewerMouseWheelScaleBehavior(double scale, EventHandler<ScaleChangedEventArgs> scaleChanged)
    {
        Scale = scale;
        this.ScaleChanged = scaleChanged;
    }
    protected override void OnAttached()
    {
        base.OnAttached();
        scrollviewer = AssociatedObject;
        scrollviewer.PreviewMouseWheel += Target_PreviewMouseWheel;
        scrollviewer.PreviewKeyDown += Scrollviewer_PreviewKeyDown;
        Content = scrollviewer.Content as FrameworkElement;
    }

    private void Scrollviewer_PreviewKeyDown(object sender, KeyEventArgs e)
    {
        if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.NumPad0)
        {
            // 當 Ctrl + NumPad0 被按下時,重置縮放比例
            OnScaleChanged(1.0);
            e.Handled = true; // 阻止事件的傳播
        }
    }

    private void OnScaleChanged(double newScale)
    {
        newScale = Math.Max(MinScale, Math.Min(newScale, MaxScale));
        if (newScale == this.Scale) return;
        double oldScale = this.Scale;
        this.Scale = newScale;
        if (Content != null)
        {
            double oldWidth = Content.Width;
            double oldHeight = Content.Height;
            Content.Width = Content.Width / oldScale * newScale;
            Content.Height = Content.Height / oldScale * newScale;

            Point mousePos = Mouse.GetPosition(Content);
            double scrollh = scrollviewer.HorizontalOffset + (Content.Width - oldWidth) * mousePos.X / oldWidth;
            double scrollv = scrollviewer.VerticalOffset + (Content.Height - oldHeight) * mousePos.Y / oldHeight;
            if (scrollh > 0)
                scrollviewer.ScrollToHorizontalOffset(scrollh);
            if (scrollv > 0)
                scrollviewer.ScrollToVerticalOffset(scrollv);
            ScaleChanged?.Invoke(scrollviewer, new ScaleChangedEventArgs(oldScale, newScale));
        }
    }

    private void Target_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        if (Keyboard.IsKeyDown(Key.LeftCtrl))
        {
            double newScale = this.Scale;
            // 使用 Ctrl 鍵時縮放
            if (e.Delta > 0)
                newScale += 0.01; // 放大
            else
                newScale -= 0.01; // 縮小
                               // 限制縮放比例在一定範圍內
            newScale = Math.Max(MinScale, Math.Min(newScale, MaxScale));
            OnScaleChanged(newScale);
            e.Handled = true; // 阻止滾輪事件的傳播
        }
    }
}
public class ScaleChangedEventArgs : EventArgs
{
    public double OldScale { get; private set; }
    public double NewScale { get; private set; }
    public ScaleChangedEventArgs(double oldScale, double newScale)
    {
        OldScale = oldScale;
        NewScale = newScale;
    }
}

使用案例:

private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
    Interaction.GetBehaviors(scrollviewer).Add(new ScrollViewerMouseWheelScaleBehavior(scale, OnMesureScale));
}

void MesureScale(object sender, ScaleChangedEventArgs args)
{
    double oldscale = args.OldScale;
    double newScale = args.NewScale;
    //foreach (FrameworkElement child in paintAreaCanvas.Children)
    //{
    //    if (child == null || child.DataContext == null) continue;
    //    var ele = child.DataContext as PaintElement;
    //    if (ele == null) continue;
    //    child.SetValue(TextElement.FontSizeProperty, ele.FontSize * newScale); // 調整字體大小
    //    child.SetValue(Canvas.LeftProperty, ele.X * newScale);
    //    child.SetValue(Canvas.TopProperty, ele.Y * newScale);
    //    child.SetValue(FrameworkElement.WidthProperty, ele.Width * newScale);
    //    child.SetValue(FrameworkElement.HeightProperty, ele.Height * newScale);
    //}
    Console.WriteLine($"縮放比例: {scale:P0}");
}