如何将自定义动画添加到 ContextMenuStrip?

Posted

技术标签:

【中文标题】如何将自定义动画添加到 ContextMenuStrip?【英文标题】:How to add custom animations to a ContextMenuStrip? 【发布时间】:2021-10-12 22:22:20 【问题描述】:

有没有办法在打开 ContextMenuStrip 时创建动画,就像在这张图片中一样?

这个动画是 WhatsApp 右键单击​​的。我不知道该怎么做。

【问题讨论】:

【参考方案1】:

您可以将 AnimateWindow 函数与 ToolStrips 一起使用,其中包括 ContextMenuStrip 类,因为它们都有句柄。 例如,您可以重现处理控件的 MouseDown 事件的 OP 中显示的动画:

Private Sub SomeControl_MouseDown(sender As Object, e As MouseEventArgs) Handles SomeControl.MouseDown
    If e.Button = MouseButtons.Right Then
        Dim ctrl = DirectCast(sender, Control)
        Dim cms = ContextMenuStrip1
        cms.Location = MousePosition
        AnimateWindow(cms.Handle, 250, AW_VER_POSITIVE Or AW_HOR_POSITIVE)
        cms.Show(ctrl, ctrl.PointToClient(MousePosition))
    End If
End Sub

这意味着您必须处理每个需要动画 ContextMenuStrip 的控件的 MouseDown 事件。如果只是一个,可能还可以接受。或者一堆可以共享相同 MouseDown 事件的控件。 但是不能将动画应用到 Form 中的所有控件,例如将 ContextMenuStrip 设置为 Form 类。

可能最好构建一个自定义控件,继承 ContextMenuStrip。 然后,您可以添加一些允许配置 ContextMenuStrip 行为的属性,添加一些受支持的动画。

我要添加一些:

OpenDownwards:在 OP 的示例图片中 OpenUpwards:相反 Expand:从中心展开菜单

幻灯片(不言自明):

SlideToRight, SlideToLeft SlideDownwards, SlideUpwards

新的公共属性:

AnimationTime:动画的速度,单位毫秒 AnimationType:动画类型。组合框选择器 AnimateInDesigner:在表单设计器中为 ContextMenuStrip 设置动画。使它更容易配置它,因为动画是在设计时显示的。 默认关闭,设置为True开启。您可能希望在配置控件后将其关闭。
Imports System.ComponentModel
Imports System.Runtime.InteropServices
Imports System.Windows.Forms

<DesignerCategory("code")>
Public Class ContextMenuStripAnimated
    Inherits ContextMenuStrip

    ' Don't remove
    Public Sub New()
    End Sub

    Public Sub New(container As IContainer)
        Me.New()
        If container Is Nothing Then
            Throw New ArgumentNullException("container is null")
        End If
        container.Add(Me)
    End Sub

    Protected Overrides Sub OnOpening(e As CancelEventArgs)
        If Not DesignMode OrElse AnimateInDesigner Then
            Dim result = AnimateWindow(Handle, AnimationTime, AnimationType)
        End If
        MyBase.OnOpening(e)
    End Sub

    <DefaultValue(False)>
    Public Property AnimateInDesigner As Boolean = False

    <DefaultValue(AnimationMode.OpenDownwards)>
    Public Property AnimationType As AnimationMode = AnimationMode.OpenDownwards

    <DefaultValue(250)>
    Public Property AnimationTime As UInteger = 250

    <Flags()>
    Public Enum AnimationMode As UInteger
        OpenDownwards = AW_HOR_POSITIVE Or AW_VER_POSITIVE
        OpenUpwards = AW_HOR_NEGATIVE Or AW_VER_NEGATIVE
        Expand = AW_CENTER
        SlideToRight = AW_SLIDE Or AW_HOR_POSITIVE
        SlideToLeft = AW_SLIDE Or AW_HOR_NEGATIVE
        SlideDownwards = AW_SLIDE Or AW_VER_POSITIVE
        SlideUpwards = AW_SLIDE Or AW_VER_NEGATIVE
    End Enum

#Region "NativeMethods"

    Private Const AW_HOR_POSITIVE As UInteger = &H1
    Private Const AW_HOR_NEGATIVE As UInteger = &H2
    Private Const AW_VER_POSITIVE As UInteger = &H4
    Private Const AW_VER_NEGATIVE As UInteger = &H8
    Private Const AW_CENTER As UInteger = &H10
    Private Const AW_HIDE As UInteger = &H10000
    Private Const AW_ACTIVATE As UInteger = &H20000
    Private Const AW_SLIDE As UInteger = &H40000
    Private Const AW_BLEND As UInteger = &H80000

    <DllImport("user32.dll", SetLastError:=true)>
    Private Shared Function AnimateWindow(hwnd As IntPtr, time As UInteger, flags As AnimationMode) As Boolean
    End Function

#End Region
End Class

要将这个新控件添加到工具箱:

在项目中添加一个类,命名为ContextMenuStripAnimated 复制此处显示的所有代码,包括Imports 指令 将其粘贴到新的 Class 文件中,替换其中的所有内容 构建项目 在 ToolBox 中找到新的 Control 并将其添加到 Form

C#版本,以防万一

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;

[DesignerCategory("code")]
public class ContextMenuStripAnimated : ContextMenuStrip

    public ContextMenuStripAnimated()  

    public ContextMenuStripAnimated(IContainer container) : this()
    
        if (container == null) 
            throw new ArgumentNullException("container is null");
        
        container.Add(this);
    

    protected override void OnOpening(CancelEventArgs e)
    
        if (!DesignMode || AnimateInDesigner) 
            var result = AnimateWindow(Handle, AnimationTime, AnimationType);
        
        base.OnOpening(e);
    

    [DefaultValue(false)]
    public bool AnimateInDesigner  get; set;  = false;

    [DefaultValue(250)]
    public uint AnimationTime  get; set;  = 250;

    [DefaultValue(AnimationMode.OpenDownwards)]
    public AnimationMode AnimationType  get; set;  = AnimationMode.OpenDownwards;

    [Flags]
    public enum AnimationMode : uint
    
        OpenDownwards = AW_HOR_POSITIVE | AW_VER_POSITIVE,
        OpenUpwards = AW_HOR_NEGATIVE | AW_VER_NEGATIVE,
        Expand = AW_CENTER,
        SlideToRight = AW_SLIDE | AW_HOR_POSITIVE,
        SlideToLeft = AW_SLIDE | AW_HOR_NEGATIVE,
        SlideDownwards = AW_SLIDE | AW_VER_POSITIVE,
        SlideUpwards = AW_SLIDE | AW_VER_NEGATIVE
    

    private const uint AW_HOR_POSITIVE = 0x1;
    private const uint AW_HOR_NEGATIVE = 0x2;
    private const uint AW_VER_POSITIVE = 0x4;
    private const uint AW_VER_NEGATIVE = 0x8;
    private const uint AW_CENTER = 0x10;
    private const uint AW_HIDE = 0x10000;
    private const uint AW_ACTIVATE = 0x20000;
    private const uint AW_SLIDE = 0x40000;
    private const uint AW_BLEND = 0x80000;

    [DllImport("user32.dll", SetLastError = true)]
    private static extern bool AnimateWindow(IntPtr hwnd, uint time, AnimationMode flags);

【讨论】:

哇,它就像魔法一样。它就像一个魅力,亲爱的吉米,谢谢你的帮助。最好的从不休息,你是最好的。

以上是关于如何将自定义动画添加到 ContextMenuStrip?的主要内容,如果未能解决你的问题,请参考以下文章

使用喷气背包导航将自定义过渡动画添加到底部导航设置

如何将自定义形状变形/动画成圆形?帆布 JS

如何将自定义视图动画化为自定义视图

如何将自定义动画作为 Flutter 进度/加载指示器?

如何将自定义挂钩添加到 Woocommerce 的自定义插件

如何将自定义事件添加到 jQuery 插件模式中