WPF实现窗口比例恒定不变小结(2)
在上一篇中讲到可以通过捕获并处理WM_EXITSIZEMOVE消息来达到保持窗口比例不变,但是必须在释放鼠标的情况下才能调整窗口比例,算不上实时调整。在上一遍还提到在窗口的SizeChanged事件中调整窗口比例,但是因为事件触发的太频繁,导致在释放鼠标后窗口又还原为拖拉之前的大小。
那能不能实现窗口比例的实时调整呢?让我们来看看下面一种方法。
其实这种方法就是结合SizeChanged事件和WM_EXITSIZEMOVE消息。让我们先来分析下这2个方式:
SizeChanged事件:
优点:能够在鼠标按下(拖拉住窗口不放)的情况下实时调整窗口;
缺点:在释放鼠标后,窗口可能会还原为拖拉之前的大小;
WM_EXITSIZEMOVE消息:
优点:在释放鼠标后,窗口能够保持拖拉后的大小;
缺点:不能实时调整窗口,只能在释放鼠标后调整窗口;
我们把这2种方式的结合起来,就能够弥补2者的缺点,达到实时保持窗口比例的效果。下面我分别列出2者的代码:
处理WM_EXITSIZEMOVE消息代码:
/// <summary>
/// 重载窗口资源加载函数
/// </summary>
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
HwndSource source = HwndSource.FromVisual(this) as HwndSource;
if (source != null)
{
// 注册窗口消息处理函数
source.AddHook(new HwndSourceHook(WinProc));
}
}
public const Int32 WM_EXITSIZEMOVE = 0x0232;
/// <summary>
///窗口消息处理函数
/// </summary>
private IntPtr WinProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, ref Boolean handled)
{
IntPtr result = IntPtr.Zero;
switch (msg)
{
// 窗口消息处理
case WM_EXITSIZEMOVE:
{
// 上下拖拉窗口
if (this.Height != LastHeight)
{
this.Width = this.Height * dAspectRatio;
}
else // 左右拖拉窗口
{
this.Height = this.Width / dAspectRatio;
}
// 把修改后的窗口大小记录下来
LastWidth = (int)this.Width;
LastHeight = (int)this.Height;
break;
}
}
return result;
}
注意:代码和上一篇一致,未修改。
处理SizeChanged事件代码:
// 声明一个定时器
private Timer timer;
/// <summary>
/// SizeChanged事件处理函数
/// </summary>
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (timer != null)
timer.Dispose();
// 注册定时器处理函数和定时器触发时间
timer = new Timer(setSize, e, 80, 100);
}
/// <summary>
/// 定时器处理函数
/// </summary>
private void setSize(object eo)
{
SizeChangedEventArgs e = eo as SizeChangedEventArgs;
if (e.WidthChanged) // 左右拖拉窗口
{
if (e.NewSize.Height != e.NewSize.Width / dAspectRatio)
{
this.Dispatcher.BeginInvoke(new Action(() => { this.Height = e.NewSize.Width / dAspectRatio; }));
}
}
else if (e.HeightChanged) // 上下拖拉窗口
{
if (e.NewSize.Width != e.NewSize.Height * dAspectRatio)
{
this.Dispatcher.BeginInvoke(new Action(() => { this.Width = e.NewSize.Height * dAspectRatio; }));
}
}
// 解除定时器
timer.Dispose();
}
注意:这里采用定时器来延迟每一次调整窗口,这是因为直接调整窗口会导致SizeChanged事件触发的太频繁了!!!会导致窗口混乱的,所以我这里采用的定时器,为每一次SizeChanged事件触发延迟了80ms,当然这个事件可以调,不过最好不要小于50ms。
好了,代码贴完了,让我们来总结一下。这篇主要阐述的就是如何通过SizeChanged事件和WM_EXITSIZEMOVE消息来达到实时保持窗口比例的效果。用SizeChanged事件实时调整窗口比例(在鼠标按下不放的情况),用WM_EXITSIZEMOVE消息来最后定下窗口大小。两者结合使用,从而达到保持窗口比例的效果。不过屏幕可能还有闪烁。
好了,今天就写到这里了。
nbsp;