旋转控件需要在主UI从数据库加载数据时旋转

tim8w

知名会员
已加入
2020年9月8日
留言内容
64
编程经验
10+
你好
我希望我的永久旋转表单(在数据库负载沉重之前提出)可以继续旋转,而主要表单却是数据库负载。我无法计算所需的时间,因此我可以继续使用“旋转进度”表单继续旋转,直到主表单完成数据库加载为止。有任何想法吗?我看了看又试了几次,但无法使这个简单的案例奏效。
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,501
地点
悉尼,澳大利亚
编程经验
10+
UI线程无法一次完成两件事。如果您希望UI线程为一种形式设置动画,则它不能以另一种形式从数据库加载数据。您需要异步从数据库中加载数据。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
为什么要使用非标准旋转形式而不是Windows标准进度栏? Windows进度栏具有显示连续重复流的模式。

正是这些非标准的UI给Windows带来了不好的声誉"inconsistent UI"并促使人们使用Mac。值得庆幸的是,尽管如此,一些不关心UI约定的程序员现在也正在Mac中创建非标准的UI,并开始使其变得不一致。
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,501
地点
悉尼,澳大利亚
编程经验
10+
我创建了一个"wait dialogue" some time ago that allows you to display a modal dialogue with a ProgressBar on the UI thread while doing other work on a background thread. Here's the user code for that form:
BackgroundWorkerForm:
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
 
namespace Wunnell.Demo.BackgroundWorkerForm.CS
{
    public partial class BackgroundWorkerForm : Form
    {
#region Fields
 
        private readonly DoWorkEventHandler onDoWork;
        private readonly ProgressChangedEventHandler onProgressChanged;
        private readonly RunWorkerCompletedEventHandler onRunWorkerCompleted;
 
#endregion Fields
 
#region Constructors
 
        /// <summary>
        /// Creates a new instance of the <see cref="BackgroundWorkerForm"/> class.
        /// </summary>
        /// <remarks>
        /// Parameterless constructor is private to ensure handlers are provided for <see cref="BackgroundWorker"/>.
        /// </remarks>
        public BackgroundWorkerForm()
        {
            InitializeComponent();
        }
 
        /// <summary>
        /// Creates a new instance of the <see cref="BackgroundWorkerForm" /> class.
        /// </summary>
        /// <param name="onDoWork">
        /// Handler for the <see cref="BackgroundWorker.DoWork">RunWorkerCompleted</see> event of a <see cref="BackgroundWorker"/>.
        /// </param>
        public BackgroundWorkerForm(DoWorkEventHandler onDoWork)
            : this()
        {
            this.onDoWork = onDoWork;
 
            // AddHandler is used for local event handlers so that remote event handlers can be registered first and thus executed first.
 
            // Remote event handlers
            backgroundWorker1.DoWork += onDoWork;
 
            // Local event handlers
            backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
        }
 
        /// <summary>
        /// Creates a new instance of the <see cref="BackgroundWorkerForm" /> class.
        /// </summary>
        /// <param name="onDoWork">
        /// Handler for the <see cref="BackgroundWorker.DoWork">RunWorkerCompleted</see> event of a <see cref="BackgroundWorker"/>.
        /// </param>
        /// <param name="onProgressChanged">
        /// Handler for the <see cref="BackgroundWorker.ProgressChanged">RunWorkerCompleted</see> event of a <see cref="BackgroundWorker"/>.
        /// </param>
        public BackgroundWorkerForm(DoWorkEventHandler onDoWork, ProgressChangedEventHandler onProgressChanged)
            : this()
        {
            this.onDoWork = onDoWork;
            this.onProgressChanged = onProgressChanged;
 
            // AddHandler is used for local event handlers so that remote event handlers can be registered first and thus executed first.
 
            // Remote event handlers
            backgroundWorker1.DoWork += onDoWork;
            backgroundWorker1.ProgressChanged += onProgressChanged;
 
            // Local event handlers
            backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
            backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
 
            // A ProgressChanged handler has been provided so the ProgressBar will be updated explicitly based on the BackgroundWorker.
            backgroundWorker1.WorkerReportsProgress = true;
            progressBar1.Style = ProgressBarStyle.Continuous;
        }
 
        /// <summary>
        /// Creates a new instance of the <see cref="BackgroundWorkerForm" /> class.
        /// </summary>
        /// <param name="onDoWork">
        /// Handler for the <see cref="BackgroundWorker.DoWork">RunWorkerCompleted</see> event of a <see cref="BackgroundWorker"/>.
        /// </param>
        /// <param name="onRunWorkerCompleted">
        /// Handler for the <see cref="BackgroundWorker.RunWorkerCompleted">RunWorkerCompleted</see> event of a <see cref="BackgroundWorker"/>.
        /// </param>
        public BackgroundWorkerForm(DoWorkEventHandler onDoWork, RunWorkerCompletedEventHandler onRunWorkerCompleted)
            : this()
        {
            this.onDoWork = onDoWork;
            this.onRunWorkerCompleted = onRunWorkerCompleted;
 
            // AddHandler is used for local event handlers so that remote event handlers can be registered first and thus executed first.
 
            // Remote event handlers
            backgroundWorker1.DoWork += onDoWork;
            backgroundWorker1.RunWorkerCompleted += onRunWorkerCompleted;
 
            // Local event handlers
            backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
        }
 
        /// <summary>
        /// Creates a new instance of the <see cref="BackgroundWorkerForm" /> class.
        /// </summary>
        /// <param name="onDoWork">
        /// Handler for the <see cref="BackgroundWorker.DoWork">RunWorkerCompleted</see> event of a <see cref="BackgroundWorker"/>.
        /// </param>
        /// <param name="onProgressChanged">
        /// Handler for the <see cref="BackgroundWorker.ProgressChanged">RunWorkerCompleted</see> event of a <see cref="BackgroundWorker"/>.
        /// </param>
        /// <param name="onRunWorkerCompleted">
        /// Handler for the <see cref="BackgroundWorker.RunWorkerCompleted">RunWorkerCompleted</see> event of a <see cref="BackgroundWorker"/>.
        /// </param>
        public BackgroundWorkerForm(
            DoWorkEventHandler onDoWork,
            ProgressChangedEventHandler onProgressChanged,
            RunWorkerCompletedEventHandler onRunWorkerCompleted)
            : this()
        {
            this.onDoWork = onDoWork;
            this.onProgressChanged = onProgressChanged;
            this.onRunWorkerCompleted = onRunWorkerCompleted;
 
            // AddHandler is used for local event handlers so that remote event handlers can be registered first and thus executed first.
 
            // Remote event handlers
            backgroundWorker1.DoWork += onDoWork;
            backgroundWorker1.ProgressChanged += onProgressChanged;
            backgroundWorker1.RunWorkerCompleted += onRunWorkerCompleted;
 
            // Local event handlers
            backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
            backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
 
            // A ProgressChanged handler has been provided so the ProgressBar will be updated explicitly based on the BackgroundWorker.
            backgroundWorker1.WorkerReportsProgress = true;
            progressBar1.Style = ProgressBarStyle.Continuous;
        }
 
#endregion Constructors
 
#region Properties
 
        public bool SupportsCancellation
        {
            set
            {
                backgroundWorker1.WorkerSupportsCancellation = value;
 
                // If the worker can be cancelled, show the Cancel button and make the form big enough to see it.
                cancelWorkButton.Visible = value;
                ClientSize = new Size(284,
                                      value ? 76 : 47);
            }
        }
 
#endregion Properties
 
#region Methods
 
        private void BackgroundWorkerForm_Shown(object sender, System.EventArgs e)
        {
            // Start the background work when the form is displayed.
            backgroundWorker1.RunWorkerAsync();
        }
 
        private void cancelWorkButton_Click(object sender, System.EventArgs e)
        {
            // Disable the button to prevent another click.
            cancelWorkButton.Enabled = false;
 
            // Cancel the background work.
            backgroundWorker1.CancelAsync();
        }
 
        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            // Update the ProgressBar.
            progressBar1.Value = e.ProgressPercentage;
        }
 
        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            // Close the form when the work is done.
            Close();
        }
 
        private void BackgroundWorkerForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            // Remote event handlers.
 
            if (onDoWork != null)
            {
                backgroundWorker1.DoWork -= onDoWork;
            }
 
            if (onProgressChanged != null)
            {
                backgroundWorker1.ProgressChanged -= onProgressChanged;
            }
 
            if (onRunWorkerCompleted != null)
            {
                backgroundWorker1.RunWorkerCompleted -= onRunWorkerCompleted;
            }
 
            // Local event handlers
            backgroundWorker1.ProgressChanged -= backgroundWorker1_ProgressChanged;
            backgroundWorker1.RunWorkerCompleted -= backgroundWorker1_RunWorkerCompleted;
        }
 
#endregion Methods
    }
}
这是一个用法示例:
Sample Usage:
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
 
namespace Wunnell.Demo.BackgroundWorkerForm.CS
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
        // This method will be executed by the BackgroundWorker in the dialogue.
        private void BackgroundWorkerForm_DoWork(object sender, DoWorkEventArgs e)
        {
            var worker = (BackgroundWorker)sender;
 
            for (var i = 0; i <= 100; i++)
            {
                if (worker.CancellationPending)
                {
                    e.Cancel = true;
 
                    break;
                }
 
                if (reportProgressCheckBox.Checked)
                {
                    worker.ReportProgress(i);
                }
 
                Thread.Sleep(100);
            }
        }
 
        // This method will be executed by the BackgroundWorker in the dialogue.
        private void BackgroundWorkerForm_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            statusLabel.Text = (e.ProgressPercentage / 100.0).ToString("p0");
        }
 
        // This method will be executed by the BackgroundWorker in the dialogue.
        private void BackgroundWorkerForm_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            statusLabel.Text = e.Cancelled
                                   ? "Operation cancelled"
                                   : "Operation complete";
        }
 
        private void runButton_Click(object sender, System.EventArgs e)
        {
            // Display the dialogue to initiate the background work.
            using (var waitDialogue = GetWaitDialogue())
            {
                waitDialogue.ShowDialog();
            }
        }
 
        private BackgroundWorkerForm GetWaitDialogue()
        {
            var dialogue = new BackgroundWorkerForm();
 
            // Only provide a ProgressChanged handler if the corresponding CheckBox is checked.
            if (reportProgressCheckBox.Checked)
            {
                dialogue = new BackgroundWorkerForm(BackgroundWorkerForm_DoWork,
                                                    BackgroundWorkerForm_ProgressChanged,
                                                    BackgroundWorkerForm_RunWorkerCompleted);
            }
            else
            {
                dialogue = new BackgroundWorkerForm(BackgroundWorkerForm_DoWork,
                                                    BackgroundWorkerForm_RunWorkerCompleted);
            }
 
            // Only display a Cancel button if the corresponding CheckBox is checked.
            dialogue.SupportsCancellation = allowCancellationCheckBox.Checked;
 
            return dialogue;
        }
    }
}
Without having seen what you're doing, I'm guessing that, in your case, you could query the database in the DoWork event handler and then bind the populated DataTable to your UI in the RunWorkerCompleted event handler.

这是设计器中对话框外观的一个想法:

1607991571348.png


这是演示表格:

1607991708893.png
 
最佳 底部