【问题标题】:Name/Term of an unknown feature未知功能的名称/术语
【发布时间】:2014-11-13 07:52:29
【问题描述】:

我想在我的应用程序中实现一个功能,问题是我不知道在哪里搜索,因为我不知道这个功能的名称/术语。

在某些应用程序中,当您将表单移动到屏幕的边框/角附近时,应用程序会自动自动附着到该边框,直到您将表单拖到边框之外以取消附着。

我没有任何应用程序示例来展示如何使用此功能,对此感到抱歉。

有人可以解释一下这个功能的名称/术语,以及我在哪里可以找到资源来检查用于实现这个功能的技术(在 WinForms 中)?

【问题讨论】:

  • 你的意思是像 Windows 7 那样吗?
  • 这有时被称为“磁性”,如果您的意思是应用程序的窗口彼此对齐。
  • @OneFineDay 谢谢,但我不确定你在说什么,我没有看到 Windows 7 shell (explorer) 这样做。
  • @CodeCaster 谢谢,我不确定是否可以,也许可以,但我找不到任何与“磁性”边界相关的内容
  • 寻找“对接”一词。此外,Windows 任务栏就是一个例子。它是一个 AppBar,您可以创建自己的。

标签: c# .net vb.net winforms forms


【解决方案1】:

该功能有时称为“捕捉”、“粘性”或“磁性”窗口,就像在 WinAmp 中使用的那样。一个示例实现可以在CodeProject: A .NET Snap To Screen Form找到。

C# 版本归结为:

[StructLayout(LayoutKind.Sequential)]
public struct WINDOWPOS
{
    public IntPtr hwnd;
    public IntPtr hwndInsertAfter;
    public int x;
    public int y;
    public int cx;
    public int cy;
    public int flags;
}

public partial class Form1 : Form
{

    private const int SnapOffset = 35;
    private const int WM_WINDOWPOSCHANGING = 70;

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_WINDOWPOSCHANGING)
        {
            SnapToDesktopBorder(this, m.LParam, 0);
        }

        base.WndProc(ref m);
    }

    private void SnapToDesktopBorder(Form clientForm, IntPtr intPtr, int widthAdjustment)
    {
        var newPosition = new WINDOWPOS();
        newPosition = (WINDOWPOS)System.Runtime.InteropServices.Marshal.PtrToStructure(intPtr, typeof(WINDOWPOS));

        if (newPosition.y == 0 || newPosition.x == 0)
        {
            return;
            // Nothing to do!
        }

        // Adjust the client size for borders and caption bar
        Rectangle ClientRect = clientForm.RectangleToScreen(clientForm.ClientRectangle);
        ClientRect.Width += (SystemInformation.FrameBorderSize.Width * 2) - widthAdjustment;
        ClientRect.Height += (SystemInformation.FrameBorderSize.Height * 2) + SystemInformation.CaptionHeight;

        // Now get the screen working area (without taskbar)
        Rectangle WorkingRect = Screen.FromControl(clientForm).WorkingArea;

        // Left border
        if (newPosition.x >= WorkingRect.X - SnapOffset && newPosition.x <= WorkingRect.X + SnapOffset)
        {
            newPosition.x = WorkingRect.X;
        }

        // Get screen bounds and taskbar height
        // (when taskbar is horizontal)
        Rectangle ScreenRect = Screen.FromControl(clientForm).Bounds;
        int TaskbarHeight = ScreenRect.Height - WorkingRect.Height;

        // Top border (check if taskbar is on top
        // or bottom via WorkingRect.Y)
        if (newPosition.y >= -SnapOffset && (WorkingRect.Y > 0 && newPosition.y <= (TaskbarHeight + SnapOffset)) || (WorkingRect.Y <= 0 && newPosition.y <= (SnapOffset)))
        {
            if (TaskbarHeight > 0)
            {
                newPosition.y = WorkingRect.Y;
                // Horizontal Taskbar
            }
            else
            {
                newPosition.y = 0;
                // Vertical Taskbar
            }
        }

        // Right border
        if (newPosition.x + ClientRect.Width <= WorkingRect.Right + SnapOffset && newPosition.x + ClientRect.Width >= WorkingRect.Right - SnapOffset)
        {
            newPosition.x = WorkingRect.Right - (ClientRect.Width + SystemInformation.FrameBorderSize.Width);
        }

        // Bottom border
        if (newPosition.y + ClientRect.Height <= WorkingRect.Bottom + SnapOffset && newPosition.y + ClientRect.Height >= WorkingRect.Bottom - SnapOffset)
        {
            newPosition.y = WorkingRect.Bottom - (ClientRect.Height + SystemInformation.FrameBorderSize.Height);
        }

        // Marshal it back
        System.Runtime.InteropServices.Marshal.StructureToPtr(newPosition, intPtr, true);
    }
}

但是代码好像有点臃肿,我觉得可以大大简化。它也只适用于桌面边框,不适用于其他窗口。

另请参阅Anyone familiar with a good “sticky windows” library for Winforms?,这两个答案都链接到其他 CodeProject 解决方案:SnapFormExtender - a magnet for your MDI child forms (2004) 和 Sticky Windows - How to make your (top-level) forms to stick one to the other or to the screen,同样来自 2004 年。

【讨论】:

  • 我注意到它在屏幕的右/下(任务栏)边缘捕捉应用程序(非客户区)的右/下边框。
  • 不要指望我支持它,我只是报告我的发现。 ;) 它让您了解如何完成它,随时为 CodeProject 提供修复或编辑这篇文章。我想例如你需要做两次SystemInformation.FrameBorderSize.WidthHeight 而不是一次。编辑:从头开始,这完全是他使用的错误属性,因为它“获取围绕正在拖动调整大小的窗口周边绘制的调整大小边框的厚度(以像素为单位)"。这不是窗口镶边大小,而是您在调整大小时看到的灰色边框。此代码已损坏。
  • 我刚刚用 this.Widththis.Height 替换了边界测量逻辑(这似乎不是必需的),现在它可以按预期工作了,感谢您的时间。
猜你喜欢
  • 2022-11-04
  • 2019-10-12
  • 2017-12-11
  • 2021-12-09
  • 2020-02-25
  • 2020-04-17
  • 2018-09-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多