WPF 调整大小完成

15

所以我需要通过过程化生成一个网格的背景图像,它只需要0.1秒。

因此,我可以将其接线到SizeChanged事件中,但是当您调整图表大小时,它会触发该事件大约30次每秒,因此调整大小事件会严重延迟。

有人知道一种好的方法来接线到调整大小事件并测试用户是否已完成调整大小吗?我尝试简单地检查鼠标的上/下状态,但是当调整大小事件发生时,鼠标几乎总是按下状态。


图片的性质是什么?它是光栅图像还是矢量图像?原因在于,根据您尝试完成的任务的性质,可能会有更好的方法。 - codekaizen
它是基于一些相当复杂的数学运算的光栅图像。我并不完全熟悉矢量艺术的能力,但现在假设它不能在XAML中完成。 - Joel Barsotti
@JoelBarsotti:最好的解决方案是在SizeChanged事件处理程序中调用“GenerateImage()”两次。 - Zahid Sattar
6个回答

25

在调整大小时,你可以启动一个短暂的计时器(例如100毫秒),在每次调整大小时重置该计时器以防止它过期。当最后一次调整大小发生时,计时器将到期,然后你可以绘制背景图像。

示例:

Timer resizeTimer = new Timer(100) { Enabled = false };

public Window1()
{
    InitializeComponent();
    resizeTimer.Elapsed += new ElapsedEventHandler(ResizingDone);
}

void ResizingDone(object sender, ElapsedEventArgs e)
{
    resizeTimer.Stop();
    GenerateImage();
}

private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
    resizeTimer.Stop();
    resizeTimer.Start();
}

1
这似乎有点像一个技巧,但嘿,一个可行的技巧比那些容易出错的完美代码要好得多。 - Joel Barsotti
1
@Joel,我猜这是唯一最简单的方法,因为窗口调整大小实际上是由Window Chrome完成的,而Window Chrome不是WPF本地窗口的一部分,因此您将无法获得任何此类鼠标抬起事件来处理。另一种选择是创建自己的Window Chrome,自己的无边框窗口样式,并在您的样式中需要重新创建整个窗口框架并编写鼠标事件的代码。 - Akash Kava
我完全支持最简单的方法,无论是否是hack,如果有10行代码几乎相同和1000行代码,我每次都会选择10行。 - Joel Barsotti

7

这里是简洁的解决方案:

private const int WmExitSizeMove = 0x232;

private void OnLoaded(object sender, RoutedEventArgs args)
{
    var helper = new WindowInteropHelper(this);
    if (helper.Handle != null)
    {
        var source = HwndSource.FromHwnd(helper.Handle);
        if (source != null)
            source.AddHook(HwndMessageHook);
    }
}

private IntPtr HwndMessageHook(IntPtr wnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    switch (msg)
    {
        case WmExitSizeMove:
            // DO SOMETHING HERE
            handled = true;
            break;
    }
    return IntPtr.Zero;
}

祝你好运!


2
对于 .Net 3.5 及以上版本,Pete Brown使用Blends System.Windows.Interactivity.dll提供的附加属性描述了一种解决方案(链接)。您可以将 Resizing 事件连接到停止生成图像,并在 Resized 事件中开始为新大小生成图像。
希望对您有所帮助。

1
我会使用Dispatcher.BeginInvoke方法。这将确保只有在应用程序有时间处理它时才生成您的图像。
private bool _generateImageReqested = false;

private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
    if (!_generateImageReqested)
    {
        _generateImageReqested = true;
        Dispatcher.BeginInvoke(new Action(GenerateImage), DispatcherPriority.ApplicationIdle);
    }
}

private void GenerateImage()
{
    _generateImageReqested = false;

    // resize your image here
}

0
你需要查看图像调整吗?你可以在鼠标抬起事件上处理调整并重新渲染图像。

那是我的第一反应,但当我尝试时,我无法弄清楚如何捕获正确的mouseup事件,我有点WPF新手,而且我正在猴子般地在别人的代码中摸索。我正在处理的代码被插入为另一个对象的子元素。据我所知,有冒泡和隧道路由事件,我需要做的是捕获隧道版本。我的理解是,这些事件通常具有Preview前缀,而我没有看到mouseleftbuttonup的前缀。 - Joel Barsotti
我找到了.PreviewMouseLeftButtonUpEvent事件,但似乎在调整大小完成后它并没有触发。 - Joel Barsotti

0
最佳解决方案是在“SizeChanged”事件处理程序中两次调用“GenerateImage()”。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接