c# - 使用从 WinForms 到 WPF 的放大 API

标签 c# wpf winforms magnification

我找到了一个 library在网络上使用 WinForms 中的 Magnification API,效果很好。我试图让它与 WPF 一起工作,但没有运气,没有异常或错误,一切似乎都很好。我开始认为它不适用于 WPF。

WinForms 代码:

public class Magnifier : IDisposable
{
    private Form form;
    private IntPtr hwndMag;
    private float magnification;
    private bool initialized;
    private RECT magWindowRect = new RECT();
    private System.Windows.Forms.Timer timer;

    public Magnifier(Form form)
    {
        if (form == null)
            throw new ArgumentNullException("form");

        magnification = 2.0f;
        this.form = form;
        this.form.Resize += new EventHandler(form_Resize);
        this.form.FormClosing += new FormClosingEventHandler(form_FormClosing);

        timer = new Timer();
        timer.Tick += new EventHandler(timer_Tick);

        initialized = NativeMethods.MagInitialize();
        if (initialized)
        {
            SetupMagnifier();
            timer.Interval = NativeMethods.USER_TIMER_MINIMUM;
            timer.Enabled = true;
        }
    }

    void form_FormClosing(object sender, FormClosingEventArgs e)
    {
        timer.Enabled = false;
    }

    void timer_Tick(object sender, EventArgs e)
    {
        UpdateMaginifier();
    }

    void form_Resize(object sender, EventArgs e)
    {
        ResizeMagnifier();
    }

    ~Magnifier()
    {
        Dispose(false);
    }

    protected virtual void ResizeMagnifier()
    {
        if ( initialized && (hwndMag != IntPtr.Zero))
        {
            NativeMethods.GetClientRect(form.Handle, ref magWindowRect);
            // Resize the control to fill the window.
            NativeMethods.SetWindowPos(hwndMag, IntPtr.Zero,
                magWindowRect.left, magWindowRect.top, magWindowRect.right, magWindowRect.bottom, 0);
        }
    }

    public virtual void UpdateMaginifier()
    {
        if ((!initialized) || (hwndMag == IntPtr.Zero))
            return;

        POINT mousePoint = new POINT();
        RECT sourceRect = new RECT();

        NativeMethods.GetCursorPos(ref mousePoint);

        int width = (int)((magWindowRect.right - magWindowRect.left) / magnification);
        int height = (int)((magWindowRect.bottom - magWindowRect.top) / magnification);

        sourceRect.left = mousePoint.x - width / 2;
        sourceRect.top = mousePoint.y - height / 2;


        // Don't scroll outside desktop area.
        if (sourceRect.left < 0)
        {
            sourceRect.left = 0;
        }
        if (sourceRect.left > NativeMethods.GetSystemMetrics(NativeMethods.SM_CXSCREEN) - width)
        {
            sourceRect.left = NativeMethods.GetSystemMetrics(NativeMethods.SM_CXSCREEN) - width;
        }
        sourceRect.right = sourceRect.left + width;

        if (sourceRect.top < 0)
        {
            sourceRect.top = 0;
        }
        if (sourceRect.top > NativeMethods.GetSystemMetrics(NativeMethods.SM_CYSCREEN) - height)
        {
            sourceRect.top = NativeMethods.GetSystemMetrics(NativeMethods.SM_CYSCREEN) - height;
        }
        sourceRect.bottom = sourceRect.top + height;

        if (this.form == null)
        {
            timer.Enabled = false;
            return;
        }

        if (this.form.IsDisposed)
        {
            timer.Enabled = false;
            return;
        }

        // Set the source rectangle for the magnifier control.
        NativeMethods.MagSetWindowSource(hwndMag, sourceRect);

        // Reclaim topmost status, to prevent unmagnified menus from remaining in view. 
        NativeMethods.SetWindowPos(form.Handle, NativeMethods.HWND_TOPMOST, 0, 0, 0, 0,
            (int)SetWindowPosFlags.SWP_NOACTIVATE | (int)SetWindowPosFlags.SWP_NOMOVE | (int)SetWindowPosFlags.SWP_NOSIZE);

        // Force redraw.
        NativeMethods.InvalidateRect(hwndMag, IntPtr.Zero, true);
    }

    public float Magnification
    {
        get { return magnification; }
        set
        {
            if (magnification != value)
            {
                magnification = value;
                // Set the magnification factor.
                Transformation matrix = new Transformation(magnification);
                NativeMethods.MagSetWindowTransform(hwndMag, ref matrix);
            }
        }
    }

    protected void SetupMagnifier()
    {
        if (!initialized)
            return;

        IntPtr hInst;

        hInst = NativeMethods.GetModuleHandle(null);

        // Make the window opaque.
        form.AllowTransparency = true;
        form.TransparencyKey = Color.Empty;
        form.Opacity = 255;

        // Create a magnifier control that fills the client area.
        NativeMethods.GetClientRect(form.Handle, ref magWindowRect);
        hwndMag = NativeMethods.CreateWindow((int)ExtendedWindowStyles.WS_EX_CLIENTEDGE, NativeMethods.WC_MAGNIFIER,
            "MagnifierWindow", (int)WindowStyles.WS_CHILD | (int)MagnifierStyle.MS_SHOWMAGNIFIEDCURSOR |
            (int)WindowStyles.WS_VISIBLE,
            magWindowRect.left, magWindowRect.top, magWindowRect.right, magWindowRect.bottom, form.Handle, IntPtr.Zero, hInst, IntPtr.Zero);

        if (hwndMag == IntPtr.Zero)
        {
            return;
        }

        // Set the magnification factor.
        Transformation matrix = new Transformation(magnification);
        NativeMethods.MagSetWindowTransform(hwndMag, ref matrix);
    }

    protected void RemoveMagnifier()
    {
        if (initialized)
            NativeMethods.MagUninitialize();
    }

    protected virtual void Dispose(bool disposing)
    {
        timer.Enabled = false;
        if (disposing)
            timer.Dispose();
        timer = null;
        form.Resize -= form_Resize;
        RemoveMagnifier();
    }

    #region IDisposable Members

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    #endregion
}

在 WPF 代码中,我刚刚修改了 Magnifer 类:

public class Magnifier : IDisposable
{
    private Window window;
    private IntPtr hwnd;
    private IntPtr hwndMag;
    private float magnification;
    private bool initialized;
    private RECT magWindowRect = new RECT();
    private DispatcherTimer timer;

    public Magnifier(Window window)
    {
        if (window == null)
            throw new ArgumentNullException("form");

        hwnd = new WindowInteropHelper(window).Handle;
        magnification = 2.0f;
        this.window = window;
        this.window.SizeChanged += form_Resize;
        this.window.Closing += form_FormClosing;

        timer = new DispatcherTimer();
        timer.Tick += timer_Tick;

        initialized = NativeMethods.MagInitialize();
        if (initialized)
        {
            SetupMagnifier();
            timer.Interval = TimeSpan.FromMilliseconds(NativeMethods.USER_TIMER_MINIMUM);
            timer.IsEnabled = true;
        }
    }

    void form_FormClosing(object sender, CancelEventArgs e)
    {
        timer.IsEnabled = false;
    }

    void timer_Tick(object sender, EventArgs e)
    {
        UpdateMaginifier();
    }

    void form_Resize(object sender, RoutedEventArgs e)
    {
        ResizeMagnifier();
    }

    ~Magnifier()
    {
        Dispose(false);
    }

    protected virtual void ResizeMagnifier()
    {
        if (initialized && (hwndMag != IntPtr.Zero))
        {
            NativeMethods.GetClientRect(hwnd, ref magWindowRect);
            // Resize the control to fill the window.
            NativeMethods.SetWindowPos(hwndMag, IntPtr.Zero,
                magWindowRect.left, magWindowRect.top, magWindowRect.right, magWindowRect.bottom, 0);
        }
    }

    public virtual void UpdateMaginifier()
    {
        if ((!initialized) || (hwndMag == IntPtr.Zero))
            return;

        POINT mousePoint = new POINT();
        RECT sourceRect = new RECT();

        NativeMethods.GetCursorPos(ref mousePoint);

        int width = (int)((magWindowRect.right - magWindowRect.left) / magnification);
        int height = (int)((magWindowRect.bottom - magWindowRect.top) / magnification);

        sourceRect.left = mousePoint.x - width / 2;
        sourceRect.top = mousePoint.y - height / 2;


        // Don't scroll outside desktop area.
        if (sourceRect.left < 0)
        {
            sourceRect.left = 0;
        }
        if (sourceRect.left > NativeMethods.GetSystemMetrics(NativeMethods.SM_CXSCREEN) - width)
        {
            sourceRect.left = NativeMethods.GetSystemMetrics(NativeMethods.SM_CXSCREEN) - width;
        }
        sourceRect.right = sourceRect.left + width;

        if (sourceRect.top < 0)
        {
            sourceRect.top = 0;
        }
        if (sourceRect.top > NativeMethods.GetSystemMetrics(NativeMethods.SM_CYSCREEN) - height)
        {
            sourceRect.top = NativeMethods.GetSystemMetrics(NativeMethods.SM_CYSCREEN) - height;
        }
        sourceRect.bottom = sourceRect.top + height;

        if (this.window == null)
        {
            timer.IsEnabled = false;
            return;
        }

        //if (this.window.IsDisposed)
        //{
        //    timer.IsEnabled = false;
        //    return;
        //}

        // Set the source rectangle for the magnifier control.
        NativeMethods.MagSetWindowSource(hwndMag, sourceRect);

        // Reclaim topmost status, to prevent unmagnified menus from remaining in view. 
        NativeMethods.SetWindowPos(hwnd, NativeMethods.HWND_TOPMOST, 0, 0, 0, 0,
            (int)SetWindowPosFlags.SWP_NOACTIVATE | (int)SetWindowPosFlags.SWP_NOMOVE | (int)SetWindowPosFlags.SWP_NOSIZE);

        // Force redraw.
        NativeMethods.InvalidateRect(hwndMag, IntPtr.Zero, true);
    }

    public float Magnification
    {
        get { return magnification; }
        set
        {
            if (magnification != value)
            {
                magnification = value;
                // Set the magnification factor.
                Transformation matrix = new Transformation(magnification);
                NativeMethods.MagSetWindowTransform(hwndMag, ref matrix);
            }
        }
    }

    protected void SetupMagnifier()
    {
        if (!initialized)
            return;

        IntPtr hInst;

        hInst = NativeMethods.GetModuleHandle(null);

        // Make the window opaque.
        //form.AllowTransparency = true; (done in xaml)
        //window.Background = Brushes.Transparent; (done in xaml)
        //window.Opacity = 255;

        // Create a magnifier control that fills the client area.
        NativeMethods.GetClientRect(hwnd, ref magWindowRect);
        hwndMag = NativeMethods.CreateWindow((int)ExtendedWindowStyles.WS_EX_CLIENTEDGE, NativeMethods.WC_MAGNIFIER,
            "MagnifierWindow", (int)WindowStyles.WS_CHILD | (int)MagnifierStyle.MS_SHOWMAGNIFIEDCURSOR |
            (int)WindowStyles.WS_VISIBLE,
            magWindowRect.left, magWindowRect.top, magWindowRect.right, magWindowRect.bottom, hwnd, IntPtr.Zero, hInst, IntPtr.Zero);

        if (hwndMag == IntPtr.Zero)
        {
            return;
        }

        // Set the magnification factor.
        Transformation matrix = new Transformation(magnification);
        NativeMethods.MagSetWindowTransform(hwndMag, ref matrix);
    }

    protected void RemoveMagnifier()
    {
        if (initialized)
            NativeMethods.MagUninitialize();
    }

    protected virtual void Dispose(bool disposing)
    {
        timer.IsEnabled = false;
        //if (disposing)
        //    timer.Dispose();
        timer = null;
        window.SizeChanged -= form_Resize;
        RemoveMagnifier();
    }

    #region IDisposable Members

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    #endregion
}

XAML:

<Window x:Class="WpfApplication11.MagnifierWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MagnifierWindow" Height="350" Width="525" AllowsTransparency="True" WindowStyle="None">

<Window.Background>
    <SolidColorBrush />
</Window.Background>

-为了使用这个类,我只是在 Form/Window 的构造函数中初始化它。

-我在 WPF 中所做的更改:

  • 添加了“hwnd”字段,在 Magnifier 构造函数中对其进行了初始化。
  • 将 System.Windows.Forms.Timer 替换为 System.Windows.Threading.DispatcherTimer。
  • 将 form.Resize 更改为 window.SizeChanged 并将 form.FormClosing 更改为 窗口。关闭。但这是无关紧要的,对吧?
  • 在 UpdateMagnifier() 中评论了 if (this.window.IsDisposed) 自 Window 中没有 IsDisposed 属性。
  • 评论了 Dispose() 中的处置检查。

-由于字符限制,我无法添加 Native 方法和结构。

帮助将不胜感激,谢谢。

最佳答案

您应该在加载窗口的 Loaded 事件中初始化您的放大镜,并且可以检索窗口句柄。否则,它始终为零。

public Magnifier(Window window)
{
    if (window == null)
        throw new ArgumentNullException("form");

    hwnd = new WindowInteropHelper(window).Handle;
    magnification = 2.0f;
    this.window = window;
    this.window.SizeChanged += form_Resize;
    this.window.Closing += form_FormClosing;

    timer = new DispatcherTimer();
    timer.Tick += timer_Tick;
    Loaded+=MainWindow_Loaded;
}

void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
    initialized = NativeMethods.MagInitialize();
    if (initialized)
    {
        handle = new WindowInteropHelper(this).Handle;
        SetupMagnifier();
        timer.Interval = TimeSpan.FromMilliseconds(NativeMethods.USER_TIMER_MINIMUM);
        timer.Start();// = true;
    }
}

关于c# - 使用从 WinForms 到 WPF 的放大 API,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11908676/

相关文章:

c# - 应用程序无法导航到 MainPage

c# - 系统参数异常 : Complex DataBinding accepts as a data source either an IList or an IListSource

c# - ToolStripCombobox.SelectionChangeCommitted 未找到

c# - 当底层匿名类型相似时,如何在Linq中合并两个列表?

javascript - 将值从 JQuery Datepicker 传递到代码隐藏

c# - WPF - 在大量控件上设置 Tab 键顺序

c# - 如何正确使用 ToggleButton.IsChecked 或 IsPressed 上的触发器?

wpf - DataGrid 排序升序 > 降序 > null(不排序)

c# - 防止列表框在更新时滚动到顶部

c# - Array.Exist() 只识别数组的最后一个元素