ZeroTouchNode with Xaml

Hello,

I’m building some ZeroTouchNodes and one node needs to show a Xaml form with a “Select Element” button. When you use Showdialog() it isn’t possible and when you use Show() the dynamo script already runs and finish while the form still shows. Anyone with experience if it can be done?

public static List<Object> UI_Interface(List<Object> list)
{
        Document doc = DocumentManager.Instance.CurrentDBDocument;
        UIDocument uidoc = DocumentManager.Instance.CurrentUIDocument;

        List<Object> listReturn = new List<Object>();

        ExampleUI example = new ExampleUI();

        example.comboBox.SelectedIndex = 0;
        example.comboBox.ItemsSource = list;

        var res = example.ShowDialog();

        if (!res.HasValue && res.Value)
            example.Close();

        var data = example.comboBox.SelectedItem;
        listReturn.Add(data);

        return (listReturn);
}

Take a look at here;

1 Like

Thanks.

But this is not what i’m trying to do. The hand-out is about building a node. I also build a node but with a Xaml menu that pops-up when running the code.
When the Xaml form pop-up i have to press on a button to select elements. In C# not that hard to acompolish. When using the same modeless technique dynamo isn’t waiting for user input and finish the script already…

you want to create a wpf-windwow and inside of it select elements?

That’ correct making a WPF is easy see this link

what does this mean?

What type is exampleUI?

Hi,

When you build an c# addin for revit and use showdialog() you can only select things in the form and not in revit. When you use show() it’s possible to keep the form open and still can do things in revit. But that doesn’t work in this case.

exampleUI refers to the wpf form (see attached link from John Pierson)

hmm, when you use showDialog you block the main thread, which is also running the Revit UI.

You could start your window on another thread… but then still the ZT node will return.

If you block in the ZT thread (main thread, UI thread), then you can’t interact with Revit, and if you don’t block the ZT thread then the node will return.

I think this won’t work.

Maybe there is someway to unblock the thread for a moment, but don’t return, and keep looping using the idle thread.
Perhaps better you could use an async await pattern to avoid blocking but because the method is a zero touch one, I’m not sure how that would work.

Hi,

When you add a form in a Python script node i saw you can do Application.Run(Form). So the form is running on top of dynamo and you can still select things in Revit.

So i tried the same technique in my C#/ WPF code (instead of ShowDialog()) and it’s working but when you close/ finish the wpf by pressing on a OK button it closes not only the WPF form but also Revit. There must be a way you can only finish the form…

ExampleUI example = new ExampleUI();

Application app = new Application();
//var res = example.ShowDialog();
app.Run(example);

Try using Showdialog() and then when the Select button is clicked use Hide() to hide the window, do the selection and use Showdialog() again.

Hi,

No when the window get’s hide the script is going to run already :frowning:

can you show the node you’re making in the context of the Dynamo graph?

Sure, This is just a simple test UI for selecting a number. When you press oke the result is 7 so that part is working fine. But when you press hide (needs to become select element) like you said dynamo continues already


dynamoUI 2

Ok, and what is the behaviour you expect?
What function is the button connected to?

I expect at the moment i press Hide i can select model elements in the project and when finished the selection the dynamo script continues.

I already can do this with C# plugins but my customer wants own dynamo nodes that can do the same

Ok, got you. So you have already implemented a selection method that is called when that button is clicked?

Yes with an external event you can select elements in the project but at the same time the dynamo script is finished without the selected elements data.

to be honest, I haven’t done that with zero touch nodes, but I have implemented different selection methods like Pick Point, Pick Face, Pick Object through python nodes in Dynamo, and it all works as expected. I don’t see a reason why it wouldn’t with a ZeroTouch node.

Yes with a python node it’s possible it works with Application.Run(form) instead of Show()

So there must be a way to do the same in a ZeroTouchNode…

clr.AddReference("RevitServices") 
import RevitServices 
from RevitServices.Persistence import DocumentManager 
from RevitServices.Transactions import TransactionManager 

clr.AddReference("RevitAPI") 
clr.AddReference("RevitAPIUI") 

import Autodesk 
import Autodesk.Revit.DB as RDB 
import Autodesk.Revit.UI as RUI 
import Autodesk.Revit.UI.Selection as RSel

doc = DocumentManager.Instance.CurrentDBDocument 
uiapp = DocumentManager.Instance.CurrentUIApplication 
app = uiapp.Application  
uidoc = uiapp.ActiveUIDocument 

clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")

import System.Drawing
import System.Windows.Forms

from System.Drawing import *
from System.Windows.Forms import *

elements =[]

class MySelectionFilter(RSel.ISelectionFilter):
	def __init__(self):
		pass
	def AllowElement(self, element):
		if element.Category.Name == "Walls":
			return True
		else:
			return False
	def AllowReference(self, element):
		return False


class UIExample(Form):
	def __init__(self):
		self.out = []
		self.selectElems = []
		self.InitializeComponent()
	
	def InitializeComponent(self):		
		self._button2 = System.Windows.Forms.Button()		
		self.SuspendLayout()		
		# 
		# button2
		# 
		
		self._button2.Location = System.Drawing.Point(27, 215)
		self._button2.Name = "button2"
		self._button2.Size = System.Drawing.Size(250, 27)
		self._button2.TabIndex = 1
		self._button2.Text = "Selecteer elementen"
		self._button2.UseVisualStyleBackColor = True
		self._button2.Click += self.Button2Click
		
		# 
		# MainForm
		# 
		self.AutoSize = True
		self.ClientSize = System.Drawing.Size(600, 253)		
		self.Controls.Add(self._button2)
		self.TopMost = True		
		self.MaximizeBox = False
		self.MinimizeBox = False
		self.Name = "MainForm"
		self.ShowIcon = False
		self.Text = "UIExample"
		self.ResumeLayout(False)
		self.PerformLayout()		
		
		
	def Button2Click(self, sender, e):
		if sender.Click:
			refs = uidoc.Selection.PickObjects(RSel.ObjectType.Element, MySelectionFilter())	
			elements.append([doc.GetElement(ref) for ref in refs])		


form = UIExample()
Application.Run(form)


OUT =  elements

it seems no way to do that, I gave up and use showdialog() finally :frowning: