Announcements

The Autodesk Community Forums has a new look. Read more about what's changed on the Community Announcements board.

transaction not commited...

sobon.konrad
Advocate

transaction not commited...

sobon.konrad
Advocate
Advocate

For some reason I can't get this to work. It looks like its all working just fine. I hit OK and elements get pinned, but then when I enter into another command this particular transaction gets rolled back and a new one starts thus unpinning my pinned elements. 

I tried chaning my transaction mode to manual and manually starting and closing transactions but then I am getting an error that states that I cannot start a new transaction outside of the current context. 

Can someone shed some light on this? 

Here's my Window:

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using Autodesk.Revit.Attributes;
using Autodesk.Revit.UI;
using Autodesk.Revit.DB;

namespace AutoPin
{
    public partial class AutoPin : System.Windows.Forms.Form
    {
        Document doc;
        FilteredElementCollector fec;
        LogicalOrFilter lorFilter;

        public AutoPin(Document doc)
        {
            this.doc = doc;

            InitializeComponent();

            updateFilter();
        }

        private void updateFilter()
        {

            List<ElementFilter> filters = new List<ElementFilter>();

            if (chkGrid.Checked)
            {
                filters.Add(new ElementClassFilter(typeof(Grid)));
            }

            if (chkLevels.Checked)
            {
                filters.Add(new ElementClassFilter(typeof(Level)));
            }

            if (chkLinks.Checked)
            {
                filters.Add(new ElementClassFilter(typeof(RevitLinkInstance)));
            }

            if (chkCADLinks.Checked)
            {
                filters.Add(new ElementClassFilter(typeof(ImportInstance)));
            }


            if (filters.Count == 0)
            {
                lblStatus.Text = "No pinnable elements";
                btnGO.Enabled = false;

                return;
            }

            btnGO.Enabled = true;

            lorFilter = new LogicalOrFilter(filters);

            fec = new FilteredElementCollector(doc);
            fec.WherePasses(lorFilter);

            lblStatus.Text = string.Format("{0} pinnable elements", fec.Count());
        }



        private void DoPin()
        {
            //using (Transaction trans = new Transaction(doc, "Pinning Elements"))
            //{
            //    trans.Start();
                foreach (Element el in fec)
                {
                    el.Pinned = true;
                }
                lblStatus.Text = string.Format("{0} elements pinned", fec.Count());
                Refresh();
            //    trans.Commit();
            //}
        }



        private void btnGO_Click(object sender, EventArgs e)
        {
            DoPin();
            this.Close();
        }

        private void chckGrid_CheckedChanged(object sender, EventArgs e)
        {
            updateFilter();
        }

        private void chkLevels_CheckedChanged(object sender, EventArgs e)
        {
            updateFilter();
        }

        private void chkLinks_CheckedChanged(object sender, EventArgs e)
        {
            updateFilter();
        }

        private void chkCADLinks_CheckedChanged(object sender, EventArgs e)
        {
            updateFilter();
        }


        private void checkAll_Clicked(object sender, EventArgs e)
        {
            foreach (System.Windows.Forms.Control c in this.Controls)
            {
                if (c.GetType() == typeof(CheckBox))
                {
                    ((CheckBox)c).Checked = true;
                }
            }
        }

        private void checkNone_Click(object sender, EventArgs e)
        {
            foreach (System.Windows.Forms.Control c in this.Controls)
            {
                if (c.GetType() == typeof(CheckBox))
                {
                    ((CheckBox)c).Checked = false;
                }
            }
        }

    }
}

Here's my command:

 

using System;
using System.Collections.Generic;
using System.Linq;

using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;


namespace AutoPin
{
    [Transaction(TransactionMode.Automatic)]

    public class CmdPinElements : IExternalCommand
    {
        public Result Execute(
          ExternalCommandData commandData,
          ref string message,
          ElementSet elements)
        {

            // Get application and document objects
            UIApplication uiApp = commandData.Application;
            Document doc = uiApp.ActiveUIDocument.Document;

            try
            {
                AutoPin form = new AutoPin(doc);
                form.Show();

                return Result.Succeeded;
            }
            // Catch any Exceptions and display them.
            catch (Autodesk.Revit.Exceptions.OperationCanceledException)
            {
                return Result.Cancelled;
            }
            catch (Exception x)
            {
                message = x.Message;
                return Result.Failed;
            }
        }
    }
}

Any help will be much appreciated. 

0 Likes
Reply
Accepted solutions (1)
1,460 Views
7 Replies
Replies (7)

arnostlobel
Alumni
Alumni

Without even looking closely into the code, I must point out one apparent problem: You cannot have our own transactions when your external command uses the Automatic transaction mode. An exception ought to be thrown when you try to start your own transaction.

 

Please be aware that we do not actually recommend using the Automatic mode, for it adds virtually nothing but disadvantages. It is also quite possible it will be eliminated in future releases.

Arnošt Löbel
0 Likes

sobon.konrad
Advocate
Advocate

OK, so when I changed the mode to Manual like so: 

 

    [TransactionAttribute(TransactionMode.Manual)]
    [RegenerationAttribute(RegenerationOption.Manual)]

and uncommented my manual transaction statement in DoPin() method like so:

 

       private void DoPin()
        {
            using (Transaction trans = new Transaction(doc, "Pinning Elements"))
            {
                trans.Start();
                foreach (Element el in fec)
                {
                    el.Pinned = true;
                }
                lblStatus.Text = string.Format("{0} elements pinned", fec.Count());
                Refresh();
                trans.Commit();
            }
        }

I am getting a pretty hefty error stating that I cannot start a new transaction outside of current scope. 

 

Thank you,

0 Likes

arnostlobel
Alumni
Alumni

OK, I looked more at the code and read your notes carefully again. It looks like your form is run in modeless mode. If that is the case, you cannot have transaction unless you are in a valid Revit-initiated API mode, such as in Idling event or external event. I suggest you look up everything yo can find on External Events. The Revit SDK samples (modeless dialog) can be a good start.

 

Good luck!

Arnošt Löbel
0 Likes

sobon.konrad
Advocate
Advocate

Can it be run in not modeless state? I believe that a modeless dialog allows me to keep the window open while I am still making changes to the Revit model. I am not really interested in that in this case. I would rather have it not allow any changes in the background until I hit OK and execute my DoPin() command. 

0 Likes

arnostlobel
Alumni
Alumni
Accepted solution

Yes, if the dialog is modal, causing the encompassing command not to finish until the dialog is dismissed, than you can have start transaction and make changes to the model. You can have only one transaction at a time - that is a global rule.

 

Modeless dialogs must be implemented differently, and as I stated already there are only two options - using the Idling event, or an external event. Both options are documented and sampled in the SDK. 

Arnošt Löbel
0 Likes

arnostlobel
Alumni
Alumni

By the way, the Regeneration attribute does nothing since Revit 2011.

Arnošt Löbel
0 Likes

sobon.konrad
Advocate
Advocate

Yes, so converting the form to modal dialog fixed the issue. Here's my External Command with the new modal call: 

 

namespace AutoPin
{
    [Transaction(TransactionMode.Manual)]
    public class CmdPinElements : IExternalCommand
    {
        public Result Execute(
          ExternalCommandData commandData,
          ref string message,
          ElementSet elements)
        {

            // Get application and document objects
            UIApplication uiApp = commandData.Application;
            Document doc = uiApp.ActiveUIDocument.Document;

            try
            {
                AutoPin form = new AutoPin(doc);
                form.ShowDialog();

                return Result.Succeeded;
            }
            // Catch any Exceptions and display them.
            catch (Autodesk.Revit.Exceptions.OperationCanceledException)
            {
                return Result.Cancelled;
            }
            catch (Exception x)
            {
                message = x.Message;
                return Result.Failed;
            }
        }
    }
}
0 Likes