简体   繁体   English

加载文件时显示带有动画gif的弹出窗口

[英]Display pop up with animated gif while loading file

The goal of my program is to load a directory into my treeview node, which takes more 10 sec(since the directory resides in a remote PC). 我程序的目标是将目录加载到我的treeview节点中,这需要花费10秒钟以上的时间(因为该目录位于远程PC中)。 During this time I shall add a pop up image of waiting. 在这段时间内,我将添加一个等待的弹出图像。 I copied the answer of this post: How can i show an image while my application is loading to my code, like: 我复制了这篇文章的答案: 我如何在应用程序加载到代码中时显示图像 ,例如:

   private void treeView2_AfterSelect(object sender, TreeViewEventArgs e)
   {
        Form f = new Form();
        f.Size = new Size(20, 25);
        Image im = Image.FromFile(@"C:\Documents and Settings\JiangC\Documenti\Immagini\loader.gif");
        f.FormBorderStyle = FormBorderStyle.None;
        f.MinimizeBox = false;
        f.MaximizeBox = false;
        f.AutoSize = true;
        PictureBox pb = new PictureBox();

        //pb.Dock = DockStyle.Fill;
        pb.SizeMode = PictureBoxSizeMode.AutoSize;
        pb.Image = im;
        pb.Location = new Point(50, 50);
        f.Controls.Add(pb);
        f.Show();
       // Application.DoEvents();
        BuildTree(directory, treeView2.Nodes, treeView2.SelectedNode);            
        f.Close();
    }

What I want to do is that during the loading (when Buildtree() method is implementing) the form f with the picturebox pb will be shown, and after loading they just disappear. 我想做的是在加载过程中(当实现Buildtree()方法时)将显示带有图片框pb的窗体f,并且在加载后它们会消失。

The first problem is in "pb.Dock = DockStyle.Fill;" 第一个问题是“ pb.Dock = DockStyle.Fill;”。 If I uncomment it, this form f will not be shown during the loading(but I can see its minimized window in the bottom of the screen). 如果我取消注释,则在加载过程中将不会显示此表格f(但是我可以在屏幕底部看到其最小化的窗口)。 Only if I take off this line the form f could be shown out. 只有在我取消这一行后,表格f才能显示出来。 The second problem is "f.Show();" 第二个问题是“ f.Show();”。 When the form f is shown, the picturebox pb isn't shown at all(just an empty hole). 当显示表格f时,根本没有显示图片框pb(只是一个空洞)。 If I modify it into "f.ShowDialog();", the form f with the picture could be shown. 如果将其修改为“ f.ShowDialog();”,则可以显示带有图片的形式f。 However here comes the third problem, which is the form f will be always there, my function "BuildTree();" 但是,这里出现了第三个问题,即形式f永远存在,即我的函数“ BuildTree();”。 isn't implemented at all! 根本没有实现!
The forth problem is if I add the line "Application.DoEvents();", it works quite fine, during the loading the form f with the picturebox will be shown and after the loading the f will disappear, but the picture in f is a gif, in this case the gif doesn't animate at all! 第四个问题是,如果我添加“ Application.DoEvents();”行,它会很好地工作,在加载过程中将显示带有图片框的表单f,并且在加载后f将消失,但是f中的图片是gif,在这种情况下,gif根本没有动画!

So anybody could help me solve the problem? 那么有人可以帮助我解决问题吗?

Here's my code of BuildTree function: 这是我的BuildTree函数代码:

private void BuildTree(DirectoryInfo[] directoryInfo, TreeNodeCollection addInMe, TreeNode clicked)
{

    for (int i = 0; i < directoryInfo.Length; i++)
    {              
        var files = directoryInfo[i].GetFiles();
        int length = files.Length;
        clicked.Nodes.Add(directoryInfo[i].Name);
        List<TreeNode> dateNode = new List<TreeNode>();
        string[] allDates = new string[length];

        try
        {
            for (int j = 0; j < length; j++)
            {
                allDates[j] = files[j].Name.Substring(11, 6);
            }

        }
        catch (Exception e)
        { }


        string[] date = allDates.Distinct().ToArray();

        for (int k = 0; k < date.Length; k++) //From here to the end
        {
            // is my code loading file
            dateNode.Add(clicked.Nodes.Add(date[i]));
            for (int j = 0; j < length; j++)
            {
                // curNode.Nodes.Add(file.FullName, file.Name);               

                if (files[j].Name.Substring(11, 6) == date[i])
                {
                    dateNode[i].Nodes.Add(files[j].FullName, files[j].Name);
                }

            }

        }

        foreach (DirectoryInfo subdir in directoryInfo[i].GetDirectories())
        {
            BuildTree(subdir, clicked.Nodes);
        }

    }

}

It depends on whether your BuildTree() method can be executed on background thread or not. 这取决于您的BuildTree()方法是否可以在后台线程上执行。 since you are passing references to properties of TreeView control I'm assuming that that code has to be executed on UI thread. 由于您要传递对TreeView控件属性的引用,因此我假设必须在UI线程上执行该代码。 In this case th only thing I can suggest to you is call Application.DoEvents(); 在这种情况下,我唯一可以建议的就是调用Application.DoEvents();。 from within BuildTree() method, for example in a loop. 从BuildTree()方法中,例如在循环中。

Also if you are making any long term calls to get data inside BuildTree() method, you should make these on background thread and synchronize with UI in any convenient way. 另外,如果要在BuildTree()方法中进行任何长期调用以获取数据,则应在后台线程上进行这些调用,并以任何方便的方式与UI同步。

[EDIT] I had a quick look at your BuildTree() method. [编辑]我快速浏览了您的BuildTree()方法。 I think in this case the best approach for you would be: 我认为在这种情况下,最适合您的方法是:

  1. declare additional data structures to hold all data recuired to fill the TreeView. 声明其他数据结构以容纳所有需要填充的数据以填充TreeView。
  2. Fill all the data on background (You can use BackgroundWorker for this) here is a good question highlighting how get results from BackgroundWorker 将所有数据填充到背景上(您可以使用BackgroundWorker进行此操作), 这是一个很好的问题,突出显示了如何从BackgroundWorker获得结果
  3. Once all data is ready, create and add all nodes to TreeView. 准备好所有数据后,创建所有节点并将其添加到TreeView。 This also will take some time, but it has to be done on UI thread. 这也将花费一些时间,但是必须在UI线程上完成。 in order to keep UI responsive you can call Application.DoEvents() inside a loop where you will be adding new nodes to the tree 为了使UI保持响应,您可以在循环中调用Application.DoEvents(),在该循环中,您将向树中添加新节点

Code in treeView2_AfterSelect() would looks like this: treeView2_AfterSelect()中的代码如下所示:

//...
f.Show();
BackgroundWorker bw = new BackgroundWorker();

bw.DoWork += (ss, ee) =>
{
    ee.Result = PrepareData(directory); // prepare all data required to build the Tree
}

bw.RunWorkerCompleted += (ss, ee) => 
{
    BuildTreeByData(ee.Result, addInMe, clicked);
    f.Close();
}

bw.RunWorkerAsync();

Add this line to your code, before calling f.Show(): 在调用f.Show()之前,将以下行添加到您的代码中:

f.Activated += (s, e) => BuildTree(directory, treeView2.Nodes, treeView2.SelectedNode);
// it's f.Shown for Windows Forms, Activated is for WPF

It subscribes an anonymous event handler to the OnShow event of your f form. 它为f窗体的OnShow事件订阅了一个匿名事件处理程序。 In this handler you simply call your method. 在此处理程序中,您只需调用您的方法。

If it doesn't work, you will have to replace the call to BuildTree here for a BackgroundWorker call , since it is possible that your BuildTree method access UI controls, and that is a big no-no. 如果不起作用,则必须在此处将对BuildTree的调用替换为BackgroundWorker调用 ,因为BuildTree方法可能会访问UI控件,这是一个很大的禁忌。 Call this code instead of f.ShowDialog: 调用以下代码代替f.ShowDialog:

BackgroundWorker bw = new BackgroundWorker();

bw.DoWork += (ss, ee) =>
{
    f.ShowDialog(this);
    BuildTree(directory, treeView2.Nodes, treeView2.SelectedNode);
}

bw.RunWorkerCompleted += (ss, ee) => f.Close();
bw.RunWorkerAsync();

And change every access and modification to your controls in BuildTree like this: 并像这样更改对BuildTree中控件的所有访问和修改:

this.Invoke((MethodInvoker) (() =>
{
    // access you control here
}));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM