首页 > 解决方案 > 表单没有正确动画

问题描述

在我的应用程序中,我有两个表单(这是我的第一个相当大的应用程序)

单击父表单中的开始按钮后,我希望显示加载面板,并完成一些逻辑。

加载面板(它只是另一个寡妇形式)包含 bunifu 加载圆圈动画(和一些文本)。逻辑部分负责从目录树中收集名称,然后替换树上 Ms.Word 文件中的一些文本。

当我在不执行逻辑的情况下打开加载面板时,加载面板会正确设置动画并且一切正常。

private void bunifuFlatButton1_Click(object sender, EventArgs e)
    {

        int x = this.Location.X+this.Width/2-75;
        int y = this.Location.Y +this.Height/2-175;
        Loader_panel LP = new Loader_panel();
        LP.Left = x;
        LP.Top = y;
        LP.Show();
        //System.Threading.Thread.Sleep(5000); \\this doesn't help animation to start

        if (FormLogic._dataList.Count > 0) \\Here Logic part starts
            {
            for (int i = 0; i < FormLogic._dataList.Count; i++)
                GetDir.GetTarget(FormLogic._dataList[i]);
            /*foreach (var directory in FormLogic._dataList)
                    GetDir.GetTarget(directory);*/
                LogList.Items.Add(DateTime.Now + "List isn't empty");// for testing
                FormLogic.ClearData();
            }
        LP.Close();
    }

启用逻辑加载面板后出现(外观不流畅),但动画不起作用(它仅在逻辑部分完成工作时才开始工作 - 我通过禁用 LP.Close() 对其进行了测试。这可能是什么原因问题 ?

附加问题。在 .NET 环境中,代码被编译为与多个处理器线程一起工作,还是我必须手动完成?

编辑 06/08/2018 7:21 CEST

我无法从 GetDir 方法访问 LogList(由于其他线程处理它)。我尝试了多个 Invoke 构造,但似乎都不起作用;/我太菜鸟了,无法弄清楚。我在下面的代码中指定了更多细节:

namespace Docr
{
    public partial class DocrForm : Form
    {
.....
private async void Button1_Click(object sender, EventArgs e)
         {

             int x = this.Location.X + this.Width / 2 - 75;
             int y = this.Location.Y + this.Height / 2 - 175;
             Loader_panel LP = new Loader_panel();
             LP.Left = x;
             LP.Top = y;
             LP.Show(); //animation

             int count = FormLogic._dataList.Count;
             var list = FormLogic._dataList;
             await Task.Run(() =>// processing logic during showing animation
             {
                 if (count > 0)
                 {
                     for (int i = 0; i < count; i++)
                     {
                         GetDir.GetTarget(list[i],LogList); // Passing LogList as and argument
                     }
                     Invoke((Action)(() => { LogList.Items.Add(DateTime.Now + "Hi LogList"); }));\\ works fine
                 }
             });

             FormLogic.ClearData();
             LP.Close();
         }
....
}

namespace DocrLogic
{
    class GetDir
    {
    .....
        static public void GetTarget(string UserDirectory, ListBox List)// passing ListBox as an Argument
        {
            var path = UserDirectory;
            var TargetDir = new DirectoryInfo(path);
            var AllDocs1 = TargetDir.GetFiles("*.doc*", SearchOption.AllDirectories);
            var ProperPrefixes = new List<string> { };
            Invoke((Action)(() => { List.Items.Add(DateTime.Now + "Hi Log List, GetDir here"); })); // THIS DOESN'T WORK
            ....
        }
    .....
    }
}

标签: c#winformsperformance

解决方案


您需要制作方法async,然后使用await等待逻辑完成。这样 LP 表格就不会被繁重的逻辑打断。

private async void bunifuFlatButton1_Click(object sender, EventArgs e)
{

    int x = this.Location.X+this.Width/2-75;
    int y = this.Location.Y +this.Height/2-175;
    Loader_panel LP = new Loader_panel();
    LP.Left = x;
    LP.Top = y;
    LP.Show();

    int count = FormLogic._dataList.Count;
    var list = FormLogic._dataList;
    await Task.Run(()=>
    {
         if(count > 0)
         {
             for (int i = 0; i < count; i++)
             {
                 GetDir.GetTarget(list[i]);
             }
             this.Invoke(() => { LogList.Items.Add(DateTime.Now + "List isn't empty"); });
         }
    });

    FormLogic.ClearData();
    LP.Close();
}

您必须通过使用访问非线程安全对象(例如 UI 对象)来使您的代码线程安全Invoke,否则,它将抛出 System.Threading.ThreadAbortException 或 System.InvalidOperationException。


调用语法可能因您的项目而异,但您可能会 看到这篇文章以了解正确的使用方法Invoke()


更新

您绝不能尝试在调用之外访问UI 对象。invoke 由System.Windows.Forms.Control最初创建该控件的线程提供并依赖于该线程。因此在其他一些随机类上调用根本不起作用

在第二部分中,您需要更改

public static void GetTarget(string UserDirectory, ListBox List)// passing ListBox as an Argument
{
   ...
   Invoke((Action)(() => { List.Items.Add(DateTime.Now + "Hi Log List, GetDir here"); })); // THIS DOESN'T WORK
}

(您需要将整个调用行作为操作参数发送)

public static void GetTarget(string UserDirectory, Action action)// passing the action as an Argument
{
   ...
   action();
}

或者

(您需要在开始之前设置Dispatcher为)LogListTask

public static Control Dispather;
public static void GetTarget(string UserDirectory)// passing the action as an Argument
{
   ...
   Dispather.Invoke((Action)(() => { List.Items.Add(DateTime.Now + "Hi Log List, GetDir here"); }));
}

推荐阅读