16

我的 C# 表单中有一个面板,我有一个按钮。当我单击按钮时,不可见的面板显示。相反,我希望面板移入或滑入。例如,当您单击组合框时,下拉列表不会弹出。我希望我的面板显示为那样。我怎样才能做到这一点 ?

4

4 回答 4

54

窗口动画是 Windows 的内置功能。这是一个使用它的类:

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

public static class Util {
    public enum Effect { Roll, Slide, Center, Blend }

    public static void Animate(Control ctl, Effect effect, int msec, int angle) {
        int flags = effmap[(int)effect];
        if (ctl.Visible) { flags |= 0x10000; angle += 180; }
        else {
            if (ctl.TopLevelControl == ctl) flags |= 0x20000; 
            else if (effect == Effect.Blend) throw new ArgumentException();
        }
        flags |= dirmap[(angle % 360) / 45];
        bool ok = AnimateWindow(ctl.Handle, msec, flags);
        if (!ok) throw new Exception("Animation failed");
        ctl.Visible = !ctl.Visible;
    }

    private static int[] dirmap = { 1, 5, 4, 6, 2, 10, 8, 9 };
    private static int[] effmap = { 0, 0x40000, 0x10, 0x80000 };

    [DllImport("user32.dll")]
    private static extern bool AnimateWindow(IntPtr handle, int msec, int flags);
}

示例用法:

    private void button2_Click(object sender, EventArgs e) {
        Util.Animate(button1, Util.Effect.Slide, 150, 180);
    }
于 2011-05-23T22:18:17.157 回答
14

如果您使用的是 .NET 4(如果不使用 Thread 替换 Task),则可以使用与此类似的功能:

    private void slideToDestination(Control destination, Control control, int delay, Action onFinish)
    {
        new Task(() =>
        {
            int directionX = destination.Left > control.Left ? 1 : -1;
            int directionY = destination.Bottom > control.Top ? 1 : -1;

            while (control.Left != destination.Left || control.Top != destination.Bottom)
            {
                try
                {
                    if (control.Left != destination.Left)
                    {
                        this.Invoke((Action)delegate()
                        {
                            control.Left += directionX;
                        });
                    }
                    if (control.Top != destination.Bottom)
                    {
                        this.Invoke((Action)delegate()
                        {
                            control.Top += directionY;
                        });
                    }
                    Thread.Sleep(delay);
                }
                catch
                {
                    // form could be disposed
                    break;
                }
            }

            if (onFinish != null) onFinish();

        }).Start();
    }

用法:

slideToDestination(sender as Control, panel1, 10, () => MessageBox.Show("Done!"));
slideToDestination(sender as Control, panel1, 0, null);

作为操作,您将发送一些布尔变量设置为 true,以便您知道动画已经完成或在它之后运行一些代码。使用空操作调用时请注意死锁。你可以在同一个控件上以相同的速度在两个不同的方向上运行两个动画,它会永远停留在原来的位置,当然两个动画同时可以使控件在某个方向上无限前进,因为 while 永远不会结束 :)

于 2011-05-23T20:28:16.693 回答
4

看看我去年写的库:

WinForm 动画库 [.Net3.5+]

一个简单的库,用于在 .Net WinForm(.Net 3.5 及更高版本)中为控件/值设置动画。基于关键帧(路径)且完全可定制。

https://falahati.github.io/WinFormAnimation/

new Animator2D(
        new Path2D(new Float2D(-100, -100), c_control.Location.ToFloat2D(), 500))
    .Play(c_control, Animator2D.KnownProperties.Location);

这会将c_control控件从 -100、-100 移动到它在 500 毫秒内处于首位的位置。

于 2016-05-19T15:43:12.627 回答
1

对于 WinForms,您可以从不在屏幕上的面板位置开始。

使用计时器,并在 Tick 事件中,将面板的位置缓慢移动到视图中,直到它位于您的预定义坐标处。

给猫剥皮的方法很多,但我就是这样做的。

于 2011-05-23T20:01:44.887 回答