BIM World
A Professional BIM Learning Platform


Enhancing Revit with Dispatcher Class: How to Add a Progress Bar

When running a program for an extended period, adding a progress bar is an effective way to prevent crashes. If your feature is currently executing, using the Dispatcher class offers a simple and efficient solution. This approach is implemented using WPF windows.

public partial class ProgressBarView : Window
{
    ExternalCommandData m_commandData = null;
    StrightRigidFrameBridgeModel m_model = null;
    Element m_element = null;
    ProgressModel m_ProgressModel;
    bool applicationCancel = false;

    public ProgressBarView(ExternalCommandData commandData, StrightRigidFrameBridgeModel model, Element elem)
    {
        InitializeComponent();
        m_commandData = commandData;
        m_model = model;
        m_element = elem;
        ProgressModel pModel = new ProgressModel();
        m_ProgressModel = pModel;
        this.DataContext = pModel;
        applicationCancel = false;
    }

    public void StrightRigidFrameBridgeCreater(ExternalCommandData commandData, StrightRigidFrameBridgeModel model, Element elem)
    {
        using (TransactionGroup transGroup = new TransactionGroup(commandData.Application.ActiveUIDocument.Document, "Create Rebar"))
        {
            transGroup.Start("Create Stright Rigid Frame Bridge");

            ICollection elementIds = new List() { elem.Id };

            for (int i = 0; i < (model.ListBoxGriderModel.Count - 1); i++)
            {
                m_ProgressModel.ProgressInfomation = "Remaining " + (model.ListBoxGriderModel.Count - 1 - i - 1).ToString() + " Segments";
                m_ProgressModel.ProgressValue = double.Parse(i.ToString()) / (model.ListBoxGriderModel.Count - 2) * 100;
                System.Windows.Forms.Application.DoEvents();

                BoxGriderModel boxGriderModelI = model.ListBoxGriderModel[i];
                BoxGriderModel boxGriderModelJ = model.ListBoxGriderModel[i + 1];

                #region Assign family parameters to corresponding family parameters
                #endregion

                Transaction transaction1 = new Transaction(commandData.Application.ActiveUIDocument.Document);
                transaction1.Start("Change Family Parameters");

                elem.LookupParameter("iH").Set(MillimetersToUnits(boxGriderModelI.XLG));  // Height of section i of variable cross-section box girder
                elem.LookupParameter("iHI5").Set(MillimetersToUnits(boxGriderModelI.DBH)); // Height of i-section bottom plate
                elem.LookupParameter("iT").Set(MillimetersToUnits(boxGriderModelI.FBH));   // Width of i-section web plate
                elem.LookupParameter("iHI1").Set(MillimetersToUnits(boxGriderModelI.TBH)); // Height of top plate of i-section
                elem.LookupParameter("jH").Set(MillimetersToUnits(boxGriderModelJ.XLG));  // Height of section j of variable cross-section box girder
                elem.LookupParameter("jHI5").Set(MillimetersToUnits(boxGriderModelJ.DBH)); // Height of j-section bottom plate
                elem.LookupParameter("jT").Set(MillimetersToUnits(boxGriderModelJ.FBH));   // Width of j-section web plate
                elem.LookupParameter("jHI1").Set(MillimetersToUnits(boxGriderModelJ.TBH)); // Height of top plate of j-section
                elem.LookupParameter("BeamLength").Set(MillimetersToUnits(boxGriderModelJ.JDCD)); // Segment length of variable section box girder
                elem.LookupParameter("detZ").Set(MillimetersToUnits(boxGriderModelI.SJGC) - MillimetersToUnits(boxGriderModelJ.SJGC)); // Height difference between two z-sections
                elem.LookupParameter("detY").Set(MillimetersToUnits(boxGriderModelI.Y_Coordinate) - MillimetersToUnits(boxGriderModelJ.Y_Coordinate)); // Height difference between two y-sections

                transaction1.Commit();

                #region Place the family with changed parameters in the corresponding position
                Transaction transaction2 = new Transaction(commandData.Application.ActiveUIDocument.Document);
                transaction2.Start("Copy the family to the corresponding location");

                XYZ point = new XYZ(MillimetersToUnits(boxGriderModelI.X_Coordinate), MillimetersToUnits(boxGriderModelI.Y_Coordinate), MillimetersToUnits(boxGriderModelI.SJGC));
                LocationPoint familyInstancePoint = elem.Location as LocationPoint;
                XYZ translationVector = point.Subtract(familyInstancePoint.Point);

                ElementTransformUtils.CopyElements(commandData.Application.ActiveUIDocument.Document, elementIds, translationVector);

                transaction2.Commit();
                #endregion

                if (applicationCancel == true)
                {
                    break;
                }
            }

            if (applicationCancel == true)
            {
                transGroup.RollBack();
                this.Close();
            }
            else
            {
                transGroup.Assimilate();
            }
        }
    }

    private double MillimetersToUnits(double value)
    {
        return UnitUtils.ConvertToInternalUnits(value, DisplayUnitType.DUT_MILLIMETERS);
    }

    private void window_Loaded(object sender, RoutedEventArgs e)
    {
        Thread thread = new Thread(execute);
        thread.Start();
    }

    private void execute()
    {
        this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, (ThreadStart)delegate ()
        {
            StrightRigidFrameBridgeCreater(m_commandData, m_model, m_element);
        });
    }

    private void cancelAsyncButton_Click(object sender, RoutedEventArgs e)
    {
        this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, (ThreadStart)delegate ()
        {
            applicationCancel = true;
        });
    }
}

The code above uses System.Windows.Forms.Application.DoEvents() to continuously switch control between threads and the main program while updating the progress bar based on the current progress.

When using the Dispatcher class, ensure you handle exceptions properly with try-catch blocks and close threads promptly.

Note: The approach shown in this code may cause some unintended behavior. You might notice components being generated one by one, which can feel awkward. To improve this, consider optimizing the code by wrapping the entire generation process within a single transaction. This is particularly important when idle programs are running, as DoEvents can allow those processes to execute, potentially causing errors. Since the original code is missing, a detailed revision is omitted here, but this guideline should help you avoid common pitfalls.

xuebim
Follow the latest BIM developments in the architecture industry, explore innovative building technologies, and discover cutting-edge industry insights.
← Scan with WeChat
Like(0) 打赏
BIM WORLD » Enhancing Revit with Dispatcher Class: How to Add a Progress Bar

Comment Get first!

Must log in before commenting!

 

BIM World, A Professional BIM Learning Platform

Stay updated on the latest architecture trends and share new building technologies.

Contact UsAbout Us

觉得文章有用就打赏一下小编吧

非常感谢你的打赏,我们将继续提供更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫

微信扫一扫

Account Login

By signing in, you agree toUser Agreement

Sign Up