调用visible = true时,Panel上的标签不可见

时间:2015-12-18 13:59:51

标签: c# winforms visual-studio

我已经尝试谷歌找到我的问题的答案,但没有找到解决方案。

我使用C#和WinForms。我创建了一个面板并为其添加了标签。此面板最初设置为myPanel.Visible = false。我点击按钮时要设置myPanel.Visible = true。该按钮正在调用一个函数。在函数调用期间,我想在面板中显示一个progessbar,所以我设置了这个myPanel.Visible = true,在函数的末尾我将它设置回myPanel.Visible = false

问题是,标签不可见。

当我没有在函数末尾设置myPanel.Visible = false时,标签是可见的,但仅在函数的末尾。

我还尝试以编程方式在所调用的函数中添加标签,但仍无法正常工作。我尝试的第二个想法是在函数调用期间使用this.PerformLayout();

似乎应用程序仅在函数调用结束时绘制标签,但我需要在函数调用期间绘制它。

感谢您的帮助。

        private void buttonAdd_Click(object sender, EventArgs e)
        {
            //Adding label to panel
            MyLabel label = new MyLabel();
            label.Text = "Test";
            label.Location = new Point(0, 0);

            progressPanel.Controls.Add(label);

            //Showing progressPanel
            progressPanel.Visible = true;

            progressBar1.Minimum = 1;
            progressBar1.Value = 1;
            progressBar1.Step = 1;

            //Some Code

            progressPanel.Visible = false;
        }

2 个答案:

答案 0 :(得分:2)

您的问题显然是您在UI线程中执行任务。因此,当此任务正常工作时,UI本身不会重新绘制。当你完成时,它仍然是隐形的。

请尝试使用BackgroundWorker。使用其ProgressChanged事件更新进度条。

如果您展示了一些代码,我可以详细了解实施情况。

<强>更新

我实际上更喜欢sstan的答案,但我答应以BackgroundWorker方式展示。如果由于某种原因您无法使用async/await

,它可能仍然有用
public partial class Form1 : Form
{
    private BackgroundWorker _backgroundWorker;
    public Form1()
    {
        InitializeComponent();
        _backgroundWorker.DoWork += DoWork;
        _backgroundWorker.RunWorkerCompleted += WorkerCompleted;
        _backgroundWorker.WorkerReportsProgress = true;
        _backgroundWorker.ProgressChanged += WorkerProgressed;
    }

    private void buttonAdd_Click(object sender, EventArgs e)
    {
        //Adding label to panel
        MyLabel label = new MyLabel();
        label.Text = "Test";
        label.Location = new Point(0, 0);

        progressPanel.Controls.Add(label);

        //Showing progressPanel
        progressPanel.Visible = true;

        progressBar1.Minimum = 0;
        progressBar1.Maximum = 100;
        progressBar1.Value = 0;
        progressBar1.Step = 1;

        // to avoid multiple starts
        buttonAdd.Enabled = false;

        // start working
        _backgroundWorker.RunWorkerAsync();        
    }
    private void DoWork(object sender, DoWorkEventArgs e)
    {
        _backgroundWorker.ReportProgress(1);

        // work

        _backgroundWorker.ReportProgress(50);

        // more work

        _backgroundWorker.ReportProgress(100);
    }
    private void WorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        progressPanel.Visible = false;
        buttonAdd.Enabled = true;
    }
    private void WorkerProgress(object sender, ProgressChangedEventArgs e)
    {
        progressBar1.Value = e.ProgressPercentage;
    }
}

如您所见,BackgroundWorker相当容易使用,但async/await更加容易,因为您不必为并行化编写如此多的代码。

答案 1 :(得分:1)

您看到的行为是正常的。只有当UI线程有机会重新绘制窗口时,可见性的更改才会生效。但是,当您的函数正在运行时,UI线程正忙,因此它无法重新绘制您的窗口。 UI线程仅在函数调用结束时释放,因此当组件的可见性更改生效时。

您需要做的是在不同的线程上执行函数的工作,以便UI函数在函数仍在运行时可以自由重绘窗口。

执行此操作的一种方法是将Task.Run()async/await关键字结合使用。以下是使用您发布的代码的基本示例:

async private void buttonAdd_Click(object sender, EventArgs e)
{
    // ....

    //Showing progressPanel
    progressPanel.Visible = true;

    progressBar1.Minimum = 1;
    progressBar1.Value = 1;
    progressBar1.Step = 1;

    // this work will happen on separate thread,
    // so the UI thread will be free to update the panel visibility
    Progress<int> progress = new Progress<int>(percentage => progressBar1.Value = percentage);
    await Task.Run(() => this.WorkToBePerformedOnSeparateThread(progress));

    progressPanel.Visible = false;
}

private void WorkToBePerformedOnSeparateThread(IProgress<int> progress)
{
    // do work...
    progress.Report(25); // Report 25% completed...

    // do more work

    progress.Report(50); // Report 50% completed...

    // more work

    progress.Report(75); // Report 75% completed...

    // etc...
}

正如Rene在评论中指出的那样,请记住,您只能在UI线程上进行UI工作。因此,在上面的示例中,您将注意到进度报告是通过Progress<T>类执行的,该类允许您从单独的线程更改进度条值(UI工作),因为它负责确保进度报告发生在UI线程上。