使用正确的方式在.NET WinForms窗体中调用AnimateWindow?

3
我正在尝试调用 AnimateWindow 来为 WinForms 窗口的显示和隐藏添加动画效果。
这里是 Win32 的翻译 副本:
private static class NativeMethods
{
   public const int AW_ACTIVATE = 0x20000;
   public const int AW_HIDE = 0x10000;
   public const int AW_BLEND = 0x80000;
   public const int AW_CENTER = 0x00000010;
   public const int AW_SLIDE = 0X40000;
   public const int AW_HOR_POSITIVE = 0x1;
   public const int AW_HOR_NEGATIVE = 0X2;

   [DllImport("user32.dll", CharSet = CharSet.Auto)]
   public static extern int AnimateWindow(IntPtr hwand, int dwTime, int dwFlags);
}

但问题在于如何将对 AnimateWindow 的调用嵌入到 WinForms 方案中。有人建议OnLoad 中实现:

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    AnimateWindow(this.Handle, 200, AW_ACTIVATE | AW_HOR_NEGATIVE | AW_SLIDE);
}

OnClosing:

protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
    base.OnClosing(e);
    if (e.Cancel == false)
    {
        AnimateWindow(this.Handle, 200, AW_HIDE | AW_HOR_POSITIVE | AW_SLIDE);
    }
}

除了它不起作用。

  • 表单在出现时不使用任何动画
  • 在隐藏期间,表单会水平滑动屏幕,然后重新出现,然后以正常方式隐藏

如何正确地将 AnimateWindow 与 WinForms 混合使用?


另请参阅

  • .NET AnimateWindow:这位用户提出了相同的问题。但由于他试图实现其他功能,人们解决了他的问题而不是回答他的问题。
  • C# WinForms AnimateWindow issue:这位用户对在子控件中使用AnimateWindow感兴趣,而不是在顶层窗口中使用。

额外闲聊

我正在浏览表单 -> 显示 -> 可见性 -> SetVisibleCore时,发现了这个错误:

i was perusing through the Form -> Show -> Visible -> SetVisibleCore, when i discovered this bug:

protected virtual void SetVisibleCore(bool value)
{
   try
   {
      HandleCollector.SuspendCollect();
      //...snip...
   }  
   finally
   {
      HandleCollector.ResumeCollect();
   }
}

很高兴知道每个人都可以引入这些微妙的错误。
2个回答

3

我认为AnimateWindow在正常工作中有其限制。例如,它与Aero的兼容性不佳,因此要动画化滑动表单,您需要将BorderStyle设置为None。另外,请确保将StartPosition设置为Manual。

简单示例:

public partial class Form1 : Form {

  public const int AW_ACTIVATE = 0x20000;
  public const int AW_HIDE = 0x10000;
  public const int AW_BLEND = 0x80000;
  public const int AW_CENTER = 0x00000010;
  public const int AW_SLIDE = 0X40000;
  public const int AW_HOR_POSITIVE = 0x1;
  public const int AW_HOR_NEGATIVE = 0X2;

  [DllImport("user32.dll", CharSet = CharSet.Auto)]
  public static extern int AnimateWindow(IntPtr hwand, int dwTime, int dwFlags);

  public Form1() {
    InitializeComponent();
  }

  private void button1_Click(object sender, EventArgs e) {
    Form toastForm = new Form();
    toastForm.ShowInTaskbar = false;
    toastForm.StartPosition = FormStartPosition.Manual;
    toastForm.FormBorderStyle = FormBorderStyle.None;
    toastForm.Size = new Size(256, 64);
    toastForm.Location = new Point(Screen.PrimaryScreen.WorkingArea.Right - toastForm.Width, 
                                   Screen.PrimaryScreen.WorkingArea.Bottom - toastForm.Height);

    Button closeButton = new Button();
    closeButton.Text = "Close";
    toastForm.Controls.Add(closeButton);
    closeButton.Click += delegate { toastForm.Close(); };

    AnimateWindow(toastForm.Handle, 200, AW_ACTIVATE | AW_HOR_NEGATIVE | AW_SLIDE);
    toastForm.Show();
  }
}

爆炸;我不是在处理一个“吐司”窗口,而是一个完整的最大化窗口。 - Ian Boyd
@IanBoyd Winforms 不会喜欢那个。 - LarsTech
我很好奇微软默认使用哪些API来执行最小化动画,考虑到AnimateWindow存在这么多问题。 - The Muffin Man

-1

我不确定你的AnimateWindow调用是做什么的,但当你需要改变与窗体相关的底层本地“东西”时,我总是使用CreateParams()重载。你可能会发现一个类似的函数来实现你想要达到的目的。

这里有一个透明的工具窗口示例,它在显示时不会激活。

Protected Overrides ReadOnly Property CreateParams() As System.Windows.Forms.CreateParams
        Get
            Dim baseParams As Windows.Forms.CreateParams = MyBase.CreateParams

            baseParams.ExStyle = baseParams.ExStyle Or NativeMethods.ExtendedWindowsStyles.WS_EX_LAYERED Or NativeMethods.ExtendedWindowsStyles.WS_EX_TRANSPARENT Or NativeMethods.ExtendedWindowsStyles.WS_EX_NOACTIVATE Or NativeMethods.ExtendedWindowsStyles.WS_EX_TOOLWINDOW

            Return baseParams
        End Get
    End Property

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