Controlling the event ElementTypeDuplicated - revit-api

I am controlling the event "application.ControlledApplication.ElementTypeDuplicated" and this event raise after the name of the new type is imputed, but after that I would like to override the result of the dialog box ( ID: "IDD_SYMBOL_ATTRIB") that were raised before the event ElementTypeDuplicated. I already try to get a Object Args and override the result inside the method that is suubscribing the event ElementTypeDuplicated, but is not working. Is there a way of doing this?
Example:
public void OnElementTypeDuplicated(object o, ElementTypeDuplicatedEventArgs args)
{
//doing things
duplicatingTypeArgs.OverrideResult(0);
}
}
}
public void OnDialogDuplicatingELement(object o, DialogBoxShowingEventArgs args)
{
if (args.DialogId=="IDD_SYMBOL_ATTRIB")
{
duplicatingTypeArgs = args;
}
}

Haven't tested this yet, but how about implementing IUpdater with "Element.GetChangeTypeElementAddition" instead subscribing to the duplicating type event

You could subscribe to the DocumentChanged event before duplicating the symbol. That will provide you with the element ids of all newly created elements. An example of using that is provided by the place family instance sample.
After the duplication, unsubscribe again.
You can use the Idling event to be notified when the duplication has terminated.

Related

Firing a caught event

This question is so obvious, and I am sure that it is so easy to solve that I wonder why no simple and easy to understand answer hes been posted yet. I’ve found answers explaining how to create a *new event, changing the event direction, -bubble, etc. However, I have not found a Q/A regarding catch a signal and then bounce it off to the user class, and then to a class that the is user of that user class and so on and so forth.
Having said that, here is my question.
My class, ClassOne, receive the signal of a button and then has to pass that signal to ClassTwo, which in turn passes the signal to ClassThree, how that heck do I do this in JavaFx.
Please note that the class must not fire a new event, but the same event that has been caught.
Below is a grammatical explanation of what I am trying to do.
Any help, and I mean any input would be most appreciated.
public class MyBoxedButton extends HBox {
private Button btn;
MyBoxedButton(){
// Initialization of all the objects
btn = new Button();
//catch the event emitted by the button
btn.setOnAction((ActionEvent e) ->{
// fire/emit the same received event
?????
});
}
}
/*
This class catches the event emitted by MyBoxedButton and then passes it to ClassThree,
but this does not work, how then can I catch the event and then re-emit it.
*/
class ClassTwo(){
private MyBoxedButton mbb;
public ClassTwo(){
mbb = new MyBoxedButton();
//catch the event emitted by MyBoxedButton
????
// re-emit the caught event
????
}
}
/*
This class catches the event emitted by ClassTwo.
The exersice is ment to show how the messages flow
form one object to a next and then to a next, so on and so forth.
*/
class ClassThree(){
private ClassTwo c2;
public ClassThree(){
c2 = new ClassTwo();
//catch the event emitted by MyBoxedButton
????
// re-emit the caught event
????
}
As long as your wrapper classes also extend Node, fireEvent should do the trick, I think.
MyBoxedButton and ClassTwo will have to provide a way to register a listener.
I've written the SimpleEventHandlerProperty helper class, which makes this easier. Here is a code snippet from a sample class which uses SimpleEventHandlerProperty to allow to register an ActionEvent handler.
private final ObjectProperty<EventHandler<ActionEvent>> onNewSampleAction = new SimpleEventHandlerProperty<>(this,
"onNewSampleAction", ActionEvent.ACTION, this::setEventHandler);
public final EventHandler<ActionEvent> getOnNewSampleAction() {
return onNewSampleActionProperty().get();
}
public final void setOnNewSampleAction(EventHandler<ActionEvent> contentChanged) {
onNewSampleActionProperty().set(contentChanged);
}
public ObjectProperty<EventHandler<ActionEvent>> onNewSampleActionProperty() {
return onNewSampleAction;
}
Then ClassTwo and ClassThree can register a listener as required.
The helper class is available at Maven Central:
<dependency>
<groupId>org.drombler.commons</groupId>
<artifactId>drombler-commons-fx-core</artifactId>
<version>0.13</version>
</dependency>

Control Events- Revit API

I would like to control events of Load Families and Create Type with revit api. Someone can give me a direction ? I don't understand very well the documentation that I read.
First you need to subscribe to an event by creating an event listener in the IExternalApplication OnStartup method.
public class AppCommand : IExternalApplication
{
public Result OnStartup(UIControlledApplication application)
{
application.ControlledApplication.FamilyLoadedIntoDocument += OnFamilyLoaded;
return Result.Succeeded;
}
}
Next you need a handler for that event:
private void OnFamilyLoaded(object sender, FamilyLoadedIntoDocumentEventArgs args)
{
// do work here
}
When finished you need to unregister the event handler:
public Result OnShutdown(UIControlledApplication application)
{
application.FamilyLoadedIntoDocument -= OnFamilyLoaded;
return Result.Succeeded;
}
The other events available that you can subscribe to are these:
http://www.revitapidocs.com/2018/b69e9d33-3c49-e895-3267-7daabab85fdf.htm
Cheers!

C++ CLI Invoke issues

I have a MainForm class (as you'd expect, it is a form) that has a text box on it. I also have another class called 'Application_Server' That does a load of other stuff (not just form-background related, quite a lot of network based stuff etc.).
The Application_Server class runs in it's own thread, but needs to be able to update the controls on the form, for this question, we will stick with just the textbox.
The problem is that even though I am executing the command to set the text of the textBox control via 'Invoke' I am still getting the following exception during runtime:
Additional information: Cross-thread operation not valid: Control
'DebugTextBox' accessed from a thread other than the thread it was
created on.
What could be causing this? I am definitely invoking a delegate within MainForm.
Here are the relevant code segments (cut down for readability):
MainForm.h:
public ref class MainForm : public System::Windows::Forms::Form {
delegate void del_updateDebugText(String^ msg);
del_updateDebugText^ updateDebugText = gcnew del_updateDebugText(this, &MainForm::postDebugMessage);
private: void postDebugMessage(String^ message);
};
MainForm.cpp:
void EagleEye_Server::MainForm::postDebugMessage(String^ message)
{
Monitor::Enter(DebugTextBox);
if (this->DebugTextBox->InvokeRequired)
{
this->Invoke(updateDebugText, gcnew array<Object^> { message });
}
else
{
this->DebugTextBox->AppendText(message);
}
Monitor::Exit(DebugTextBox);
}
And finally, the code calling it:
void ServerAppManager::postDebugMessage(System::String^ message)
{
mainFormHandle->updateDebugText(message);
}
void ServerAppManager::applicationStep()
{
postDebugMessage("Starting\n");
// This is Run in seperate thread in MainForm.cpp
while (s_appState == ApplicationState::RUN)
{
postDebugMessage("Testing\n");
}
}
Thanks!
From background worker called bwSearch we do the call as following from the DoWork event handler:
private: System::Void bwSearch_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
//... logic
UpdateTxtOutput("Some message");
//... more logic
}
I have a RitchTextBox called txtOutput, also the windows form control containing this code is called frmMain, the UpdateTxtOutput is defined in three parts as follows:
delegate void UpdateTxtOutputDelegate(String^ text);
void UpdateTxtOutput(String^ text)
{
UpdateTxtOutputDelegate^ action = gcnew UpdateTxtOutputDelegate(this, &frmMain::Worker);
this->BeginInvoke(action, text);
}
void Worker(String^ text)
{
txtOutput->AppendText("\t" + text + "\n");
}
I managed to get it working by simplifying the method within the 'MainForm' class to:
void EagleEye_Server::MainForm::postDebugMessage(String^ message)
{
Monitor::Enter(DebugTextBox);
DebugTextBox->AppendText(message);
Monitor::Exit(DebugTextBox);
}
And then moving the 'Invoke' call to the method calling the delegate, not pretty but it works for now. I think the issue may have been caused by the form getting stuck inside an Invoke loop. I say this as I noticed that the form would lock up and stop responding after it hit the recursive Invoke statement.

How can I execute code from the Release / Release All buttons in the Release AR Documents screen

I've got a customization to the Invoice & Memo screen where I execute some custom code (web service calls) when the Release action is activated. This works fine - I knew how to replace the PXAction code and proceeded from there. Now I want to use the Release AR Documents processing screen to do the same thing, but I'm having trouble understanding where / what to override, or where to place my code.
I see the ARDocumentRelease graph constructor with the SetProcessDelegate in the source code, but I'm not sure how to proceed - whether this is where I need to be looking or not. I need to execute my code for each line being released, using the RefNbr in my code.
Since it's an static method, you can't override it. Also, you can't do like it's done in the T300, because you are in processing graph and you can't override the release button with your own. I was able to achieve it by passing callback for each AR document that have been processed.
You can call the Initialize method of the ARDocumentRelease graph to override the logic like you said. After you just have to call ReleaseDoc that uses a callback parameter instead of using the default one.
Here's the code that I came with:
public class ARDocumentRelease_Extension : PXGraphExtension<ARDocumentRelease>
{
public override void Initialize()
{
ARSetup setup = Base.arsetup.Current;
Base.ARDocumentList.SetProcessDelegate(
delegate (List<BalancedARDocument> list)
{
List<ARRegister> newlist = new List<ARRegister>(list.Count);
foreach (BalancedARDocument doc in list)
{
newlist.Add(doc);
}
AddAdditionalLogicToRelease(newlist);
}
);
Base.ARDocumentList.SetProcessCaption("Release");
Base.ARDocumentList.SetProcessAllCaption("Release All");
}
public delegate void PostPorcessing(ARRegister ardoc, bool isAborted);
private void AddAdditionalLogicToRelease(List<ARRegister> newlist)
{
ARDocumentRelease.ReleaseDoc(newlist, true, null, delegate(ARRegister ardoc, bool isAborted) {
//Add your logic to handle each document
//Test to check if it was not aborted
});
}
}
Please note that you must always call static methods from within long running process and create necessary objects there.
Processing delegate logic is implemented as long running process which creates worker thread to execute the processing logic.
You have AddAdditionalLogicToRelease() method which requires object instance in order to call and will fail during thread context switches and hence the issue. So, you must have create object instance inside the thread context and then call instance method.
In general, method that gets called from long running processes are declared static and required objects/graphs are created inside this static method to do some work. See below example how to properly override ARDocumentRelease graph for this purpose:
public class ARDocumentRelease_Extension : PXGraphExtension<ARDocumentRelease>
{
public override void Initialize()
{
Base.ARDocumentList.SetProcessDelegate(
delegate (List<BalancedARDocument> list)
{
List<ARRegister> newlist = new List<ARRegister>(list.Count);
foreach (BalancedARDocument doc in list)
{
newlist.Add(doc);
}
// use override that allows to specify onsuccess routine
ARDocumentRelease.ReleaseDoc(newlist, true, null, (ardoc, isAborted) =>
{
//Custom code here, such as create your GL
});
}
);
}
}
I think it's the function
public static void ReleaseDoc(List<ARRegister> list, bool isMassProcess, List<Batch> externalPostList, ARMassProcessDelegate onsuccess)
under ARDocumentRelease businesss logic.

Garbage collecting issue with Custom viewbinding in mono touch and mvvmcross

I have a custom calendar control for which there is an custom viewbinding. In this viewbinding we hook up some events which are not decoupled correct and therefor is the garbage collecting not completed. In the following is our custom view binding. As you can see the event is hooked up in the constructor and decoupled in the OnSelectedDate event is triggered(the user selects an date). Therefore if you choose a date the event is decouple correct and garbage collected but if you just go back, the event is still hooked up and no garbage collecting is performed. I thought about trigger the event with null values and and thereby decoulpe the event. But I think there must be some more clever way to achieve this.
namespace CmsApp.Core.Binders
{
public class CalendarViewBinding:MvxBaseTargetBinding
{
private CalendarView _calendarView;
private DateTime _currentValue;
public CalendarViewBinding(CalendarView calendarView)
{
_calendarView = calendarView;
_calendarView.OnDateSelected+=OnDateSelected;
}
protected override void Dispose(bool isDisposing)
{
if(_calendarView!=null)
{
_calendarView.OnDateSelected -= OnDateSelected;
_calendarView = null;
}
base.Dispose(isDisposing);
}
private void OnDateSelected(object sender, SelectedDateEventArgs args)
{
_currentValue = args.SelectedDate;
this.FireValueChanged(_currentValue);
_calendarView.OnDateSelected -= OnDateSelected;
}
public override void SetValue(object value)
{
var date = (DateTime)value;
_currentValue = date;
_calendarView.SelectedDate = _currentValue;
}
public override Type TargetType
{
get
{
return typeof(DateTime);
}
}
public override MvxBindingMode DefaultMode
{
get
{
return MvxBindingMode.TwoWay;
}
}
}
}
Any help is appreciated :)
It looks to me like your binding is almost correct.
The only issue I can see is that it unsubscribes from the event too often - you can't call _calendarView.OnDateSelected -= OnDateSelected; twice - but I don't think this is the problem you are seeing.
I currently would guess that the problem is not in the code you are using:
either there's a bug in the binding code in the underlying framework you are using
or something is a bug/issue in the way you are using this binding
or your memory leak has nothing to do with this binding
It's not easy to test this from the limited code posted here, but it would be simpler if you could produce a simple app that reproduces the leak you are seeing. Share that and you might be able to get more feedback.
If you believe my guesses are wrong, then the only thing I can suggest is that you switch to WeakReferences inside your binding - but this feels like a sticking plaster rather than a cure.
Just adding a link to when to release objects in mono touch / mvvmcross

Resources