代码之家  ›  专栏  ›  技术社区  ›  A G

Winforms异步更新UI模式-需要概括

  •  4
  • A G  · 技术社区  · 14 年前

    主窗体中的代码。

        public delegate void UpdateMainProgressDelegate(string message, bool isProgressBarStopped);
    
                private void UpdateMainProgress(string message, bool isProgressBarStopped)
                {
                    // make sure we are running on the right thread to be
                    // updating this form's controls.
                    if (InvokeRequired == false)
                    {
                        // we are running on the right thread.  Have your way with me!
                        bsStatusMessage.Caption = message + " [ " + System.DateTime.Now.ToShortTimeString() + " ]";
                        progressBarStatus.Stopped = isProgressBarStopped;
                    }
                    else
                    {
                        // we are running on the wrong thread.  
                        // Transfer control to the correct thread!                
                        Invoke(new ApplicationLevelValues.UpdateMainProgressDelegate(UpdateMainProgress), message, isProgressBarStopped);
                    }
                }
    

    子窗体

    private readonly ApplicationLevelValues.UpdateMainProgressDelegate _UpdateMainForm;
    private void btnX_Click(object sender, EventArgs e)
            {
                _UpdateMainForm.BeginInvoke("StartA", false, null, null);
                try
                {
                    if(UpdateOperationA())
                    { _UpdateMainForm.BeginInvoke("CompletedA", true, null, null); }
                    else
                    { _UpdateMainForm.BeginInvoke("CanceledA", true, null, null); }
                }
                catch (System.Exception ex)
                {
                    _UpdateMainForm.BeginInvoke("ErrorA", true, null, null);
                    throw ex;
                }
            }
    

    3 回复  |  直到 14 年前
        1
  •  4
  •   Nicole Calinoiu    14 年前

    如果您的操作都可以表示为单个委托类型,那么这实际上只是一个简单的重构问题。例如。:

    private void RunOperationWithMainProgressFeedback(
        Func<bool> operation,
        string startMessage,
        string completionMessage,
        string cancellationMessage,
        string errorMessage)
    {
        this._UpdateMainForm.BeginInvoke(startMessage, false, null, null);
        try
        {
            if (operation.Invoke())
            {
                this._UpdateMainForm.BeginInvoke(completionMessage, true, null, null);
            }
            else
            {
                this._UpdateMainForm.BeginInvoke(cancellationMessage, true, null, null);
            }
        }
        catch (Exception)
        {
            this._UpdateMainForm.BeginInvoke(errorMessage, true, null, null);
            throw;
        }
    }
    
    private void btnX_Click(object sender, EventArgs e)
    {
        this.RunOperationWithMainProgressFeedback(
            this.UpdateOperationA,
            "StartA",
            "CompletedA",
            "CanceledA",
            "ErrorA");
    }
    

    虽然可以使用字典来存储参数值(正如VinayC先前的回答中所建议的那样),但这并不是必需的。就我个人而言,出于可读性和性能两方面的原因,我会避免使用它,但是。。。

        2
  •  2
  •   VinayC    14 年前

    您可以创建一个字典/列表,其中包含每个按钮的相关详细信息。这些细节将包括操作名和调用操作的委托等。现在您可以为所有按钮提供通用事件处理程序,这些按钮将查找字典以获取操作名和要执行的操作。

        3
  •  1
  •   Glenn    14 年前

    我厌倦了一遍又一遍地解决这个完全相同的问题,所以我编写了一组通用的类来解决这个问题。基本思想是:

    • 创建一个抽象的Progress对象,其中包含您关心的字段,如statusMessage。

    • 在您的特定用法中,子类Progress并根据需要添加字段。然后对Job进行子类化,以保存要执行的操作,并实现UpdateProgress。

    通常,计时器对于ui更新来说已经足够好了,采用pull-and-sync ui模型比使用push-changes模型更简单。Pull-and-sync用户界面避免了很多交叉线程问题,并避免了用户界面进入奇怪的状态。

    好处:使您的进度对象成为inotifypropertychanged并进行数据绑定。(这就是您可能不想使用IDictionary的原因)。