Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Register Dockable Panel at Startup #1184

Closed
Dre-Tas opened this issue Mar 10, 2021 · 14 comments
Closed

Register Dockable Panel at Startup #1184

Dre-Tas opened this issue Mar 10, 2021 · 14 comments
Labels
Question This is a question and not an issue

Comments

@Dre-Tas
Copy link
Contributor

Dre-Tas commented Mar 10, 2021

Is there a way to run an OnStartup method (inside a IExternalApplication class) when Revit is starting up, through pyRevit?
I am trying to register a Dockable Panel, but because this happens on startup and pyRevit only runs commands I'm struggling to understand how to do it.

In a standalone C# application (without pyRevit) I would do something like this:

    public class Ribbon : IExternalApplication
    {
        public Result OnStartup(UIControlledApplication application)
        {
            // Register Dockable Panel
            MyDockablePaneldockablePane = new MyDockablePanel();
            DockablePaneId paneId = new DockablePaneId(Guid.NewGuid());
            application.RegisterDockablePane(paneId, "My Dockable Panel", dockablePane);
        }

        public Result OnShutdown(UIControlledApplication application)
        {
            return Result.Succeeded;
        }
    }

I have read about startup.* scripts that you can have at .extension level, but there aren't many examples in C# so I'm not being successful at using it.
(Biggest problem while I try this is that pyRevit doesn't find the type MyDockablePanel even though it is in one of the dlls in a subfolder of the lib folder)

I've also seen this issue here #1027 so I'd be curious to see how they did that.

Any help? :)

@eirannejad
Copy link
Collaborator

Check this out. I just added an example to the pyRevitDev extension startup.py script:

Register Panel Code

from pyrevit.framework import Windows
from pyrevit.framework import wpf
from pyrevit.coreutils import Guid


class DockableExample (Windows.Controls.Page):
    def __init__(self, xaml_file):
        wpf.LoadComponent(self, op.join(op.dirname(__file__), xaml_file))

    def do_something(self, sender, args):
        forms.alert("DockableExample Action")



class DockableExamplePanelProvider (UI.IDockablePaneProvider):
    def SetupDockablePane(self, data):
        # https://apidocs.co/apps/revit/2021.1/cde36571-ccf1-f628-9e34-6a720388d348.htm
        data.FrameworkElement = DockableExample("DockableExample.xaml")
        data.VisibleByDefault = True


DOCKABLE_PANE_ID = UI.DockablePaneId(Guid.NewGuid())
HOST_APP.uiapp.RegisterDockablePane(
    DOCKABLE_PANE_ID,
    "pyRevit Dockable Panel Example",
    DockableExamplePanelProvider()
)

Panel XAML file

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      Background="White">
    <StackPanel Margin="20">
        <TextBlock Text="pyRevit Dockable Panel Example" />
        <Button Content="Do Something" Click="do_something" HorizontalAlignment="Stretch" VerticalAlignment="Center" Height="50" Margin="0,10,0,0"/>
    </StackPanel>
</Page>

It will create a panel like this

Screen Shot 2021-03-13 at 7 03 35 PM

@eirannejad eirannejad added the Question This is a question and not an issue label Mar 14, 2021
@eirannejad eirannejad changed the title Register Dockable Panel at startup Register Dockable Panel at Startup Mar 14, 2021
@Dre-Tas
Copy link
Contributor Author

Dre-Tas commented Mar 14, 2021

Thanks Ehsan.

I already have my dockable panel and logic and it's all in C#. Any examples? Even better if it creates types from DLLs in the lib folder

@eirannejad
Copy link
Collaborator

You should be able to import the dotnet dll using clr.AddReference (it has other variations too that can accept exact path of the dll). Then import your dockable type and use the rest of the script in the script.py to instantiate and register:

class DockableExamplePanelProvider (UI.IDockablePaneProvider):
    def SetupDockablePane(self, data):
        data.FrameworkElement = YourImportedDockableType()
        data.VisibleByDefault = True


DOCKABLE_PANE_ID = UI.DockablePaneId(Guid.NewGuid())
HOST_APP.uiapp.RegisterDockablePane(
    DOCKABLE_PANE_ID,
    "pyRevit Dockable Panel Example",
    DockableExamplePanelProvider()
)

@Dre-Tas
Copy link
Contributor Author

Dre-Tas commented Mar 15, 2021

I tried the code above and it kinda works. Problem is, it creates the dockable panel twice 😕
image

Also, so no way of doing it C#?
I also need to add an event handling method at startup and it's all in C# and I didn't really wanted to translate it to python.

@eirannejad
Copy link
Collaborator

What I'm not following is your question about C#. If that's the case why are you using pyRevit? Just register the panel in your C# addon startup. It's the same mechanism shown above in python

@Dre-Tas
Copy link
Contributor Author

Dre-Tas commented Mar 16, 2021

Yeah sorry fair question. My bad in poorly explaining my issue.

The reason is that my application is all in C# and I use pyRevit to host/run it (it is part of a bigger set of tools all in pyRevit, but it is fairly more complex than the rest).
If I register the panel in the usual way (without pyRevit) I would have to use an addin file that points to a dll described in the <Assembly> tag. Once Revit opens, it looks for all the addins and loads all the dlls that are mentioned in the addins. Doing that, Revit blocks those dlls. You can't change anything there.
If anyone works on the code for that tool and pushes the changes to the repo and then the user clicks update to grab the latest dlls from the repo, that dll that Revit points to won't update, because it's been blocked by being referenced in the addin.

So this is exactly the reason. If I load the dockable panel through pyRevit, in its startup script, Revit is not blocking any dll so I can freely work on the the code and just have the users to click the update button when I make changes.

I hope it's a bit clearer now?

@eirannejad
Copy link
Collaborator

I think so. Have you tried using clr.AddReferenceToFileAndPath to manually load the specific dll? Then you canimport the namespace in that dll

@Dre-Tas
Copy link
Contributor Author

Dre-Tas commented Mar 19, 2021

Yeah I did and it works in python but if I do a using statement (not clr.AddReferenceToFileAndPath) when I try to get the script.cs working it doesn't find it.

Could it be because the dll is not in the lib folder but one of its subfolders?

@eirannejad
Copy link
Collaborator

Oh yeah it needs to be inside the bin/ directory in your extension.
https://www.notion.so/pyrevitlabs/Bundle-Lib-bin-f9c427c358ff4954bd671530973e3959

@Dre-Tas
Copy link
Contributor Author

Dre-Tas commented Mar 21, 2021

Still doesn't work for some reason. No idea why

@eirannejad
Copy link
Collaborator

Do you want to send me something to test? You can send to my gmail

@Dre-Tas
Copy link
Contributor Author

Dre-Tas commented Mar 22, 2021

Mate if you're happy to do that it would be amazing! I'll send it through now

@BIMONE-OUTILS
Copy link

BIMONE-OUTILS commented Mar 24, 2021

@eirannejad
I don't wan't to pollute the subject but I wanted to try out the dockable panel test and could not figure out how. (I checked notion and all first 🔢 )
my pyrevit dev extension is enabled.

@eirannejad
Copy link
Collaborator

@BIMONE-OUTILS So this is part of pyRevitdev extension which is not installed by default. You'd need a full clone of pyRevit git repo and attach that to Revit.

See this for a bit more info on how to clone
https://discourse.pyrevitlabs.io/t/how-to-simple-install-and-use-of-a-different-branch-of-pyrevit-github/28

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question This is a question and not an issue
Projects
None yet
Development

No branches or pull requests

3 participants