I found a library on the web using Magnification API in WinForms, its working great. I tried to make it work with WPF but no luck, there was no exceptions or errors, everything seems Ok. I'm beginning to think it was not meant to work with WPF.
WinForms Code:
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
}
In WPF Code I just modified the Magnifer class:
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>
-To use the class I just initialize it in Form/Window's constructor.
-Changes I made in WPF:
- Added "hwnd" field, initialized it in Magnifier constructor.
- Replaced System.Windows.Forms.Timer with System.Windows.Threading.DispatcherTimer.
- Changed form.Resize to window.SizeChanged and form.FormClosing to window.Closing. but this is irrelevant right?
- Commented if (this.window.IsDisposed) in UpdateMagnifier() since there's no IsDisposed property in Window.
- Commented a disposing check in Dispose().
-I couldn't add Native methods and structures because of characters limit.
Help would be greatly appreciated, thanks.
to use this Magnifier class in windowsform.