Revit C#: Copy existing button to my Ribbon - c#

I want to use the Create-Wall-Button from Architecture in my Ribbon.
I've tried debugging and found the splitbutton here: Autodesk.Windows.ComponentManager.Ribbon.Tabs[0].Panels[1].Source.Items[0]
How can I copy this SplitButton to my Ribbon or what I have to call in a new Button to use this function?
Thank you.

It is posible to clone an built-in command button and add it to another tab, however you would need a couple of tricks and of course the non-supported Autodesk.Windows dll.
I think what you are looking for is the method PostCommand from the UIApplication. Just create a new command and the requested Postable Command will be executed after your own command is completed:
var app = cmdData.Application;
var cmdId = RevitCommandId.LookupPostableCommandId(PostableCommand.StructuralWall);
app.PostCommand(cmdId);

Related

Is this a way to show a modeless dialog from a dockable pane using WPF?

I'm building a Revit plugin. It consists of a dockable pane that (among other elements) has a button. I want to open a new, separate window when a user clicks this button.
At the moment, i create a new Window, but i don't know if that's the right way to go, because now i see two Revit icons on a task bar. I do not have experience as Revit user, i'm new to Revit development, so i'm not sure if this should be the case (two icons) and as silly as it sounds, i do not have admin rights to install random addins and get a feeling of expected user experience.
I create a Window using the following code:
ParametersMissingValueWindow parametersMissingValueWindow = new ParametersMissingValueWindow();
parametersMissingValueWindow.Show();
Based on the understanding of a dockable pane that i have, i think i do not want to create another dockable pane, but just a simple modeless dialog. I wasn't able to find any examples using WPF. Hence, any information whether this is the way to go or help on how to achieve this is highly appreciated.
The Show method takes an optional parent window argument. Specify the Revit main window as the parent window, and your modeless dialogue will be recognised as belonging to the running Revit process. It is accessible from the MainWindowHandle property.
var MyWindow = new MyWindow();
HwndSource hwndSource = HwndSource.FromHwnd(UIApplication.MainWindowHandle);
Window wnd = hwndSource.RootVisual as Window;
if (wnd != null)
{
MyWindow.Owner = wnd;
//MyWindow.ShowInTaskbar = false;
MyWindow.Show();
}
It's not necessary to assign a value to ShowInTaskbar property, but it actually achieves what i wanted to do from the beginning (have only one program open in taskbar), so i left it as part of the solution, but commentted out.
Big thanks to Jeremy Tammik for pointing out the parent property.
You can use WPF to setup a window to use in revit.
MyWPF menu = new menu();
System.Windows.Window wind = new System.Windows.Window();
wind.ShowDialog(); //--> the window shows up and make stuff for revit
if you need the menu to be a dockable one check this source.
Perhaps is not up to date and you will need to adapt the code to the new api.

How to use resources in C# Visual Studio? [duplicate]

How do I create a resource that I can reference and use in various parts of my program easily?
My specific problem is that I have a NotifyIcon that I want to change the icon of depending on the state of the program. A common problem, but one I've been struggling with for a long time.
Well, after searching around and cobbling together various points from around StackOverflow (gee, I love this place already), most of the problems were already past this stage. I did manage to work out an answer to my problem though.
How to create a resource:
In my case, I want to create an icon. It's a similar process, no matter what type of data you want to add as a resource though.
Right click the project you want to add a resource to. Do this in the Solution Explorer. Select the "Properties" option from the list.
Click the "Resources" tab.
The first button along the top of the bar will let you select the type of resource you want to add. It should start on string. We want to add an icon, so click on it and select "Icons" from the list of options.
Next, move to the second button, "Add Resource". You can either add a new resource, or if you already have an icon already made, you can add that too. Follow the prompts for whichever option you choose.
At this point, you can double click the newly added resource to edit it. Note, resources also show up in the Solution Explorer, and double clicking there is just as effective.
How to use a resource:
Great, so we have our new resource and we're itching to have those lovely changing icons... How do we do that? Well, lucky us, C# makes this exceedingly easy.
There is a static class called Properties.Resources that gives you access to all your resources, so my code ended up being as simple as:
paused = !paused;
if (paused)
notifyIcon.Icon = Properties.Resources.RedIcon;
else
notifyIcon.Icon = Properties.Resources.GreenIcon;
Done! Finished! Everything is simple when you know how, isn't it?
The above didn't actually work for me as I had expected with Visual Studio 2010. It wouldn't let me access Properties.Resources, said it was inaccessible due to permission issues. I ultimately had to change the Persistence settings in the properties of the resource and then I found how to access it via the Resources.Designer.cs file, where it had an automatic getter that let me access the icon, via MyNamespace.Properties.Resources.NameFromAddingTheResource. That returns an object of type Icon, ready to just use.
The above method works well.
Another method (I am assuming web here) is to create your page. Add controls to the page. Then while in design mode go to: Tools > Generate Local Resource. A resource file will automatically appear in the solution with all the controls in the page mapped in the resource file.
To create resources for other languages, append the 4 character language to the end of the file name, before the extension (Account.aspx.en-US.resx, Account.aspx.es-ES.resx...etc).
To retrieve specific entries in the code-behind, simply call this method: GetLocalResourceObject([resource entry key/name]).
Code posted by Matthew Scharley has a memory leak:
paused = !paused;
if (paused)
notifyIcon.Icon = Properties.Resources.RedIcon;
else
notifyIcon.Icon = Properties.Resources.GreenIcon;
You should Dispose() notifyIcon.Icon before replacing it, because Properties.Resources.SOME_ICON creates a new Icon each time it is used.
This can be observed in the log, with this code:
Console.WriteLine(Properties.Resources.RedIcon.GetHashCode());
Console.WriteLine(Properties.Resources.RedIcon.GetHashCode());
Console.WriteLine(Properties.Resources.RedIcon.GetHashCode());
You will see 3 different Hash Codes in the log. This means these are different Objects.
So, the simple fix will be:
paused = !paused;
notifyIcon.Icon?.Dispose();
notifyIcon.Icon = paused
? Properties.Resources.RedIcon;
: Properties.Resources.GreenIcon;

How to manipulate a control without any pattern implemented?

I'm trying to implement the automation test via UIAutomation for our project. But lots of the controls are not standrad, and proper patterns are also not implemented for that controls. How should I to manipulate the controls via UIAutomation framework in this case?
For example, a button in our product is implemented via a Pane, and the invoked pattern is not implemented as well. How should I click the button? (To avoid installing VS on the test machine, I don't want to use Mouse.Click() in Microsoft.VisiualStudio.TestTools.UITesting namespace) Is there a way to do that only using UIAutomation framework or something else embedded in .net framework? Thanks in advance! (If the proper pattern is implemented, Below code will work. And as a new user, I cannot post the screenshot for your reference, sorry!)
object temp = null;
if (btnTest.TryGetCurrentPattern(InvokePattern.Pattern, out temp))
{
InvokePattern btnTestPattern = temp as InvokePattern;
btnTestPattern.Invoke();
}
The only way to interact when Control Patterns are not implemented is to go clicking around stuff.
I would suggest try following to avoid maximum errors.
Before sending the click, make sure the parent of button(pane or window is set to foreground)
Instead of sending the click to corner of the AutomationElement, try sending it in midpoint, of the element,
Also, try hovering over the element first, the wait like 200ms, and then send click, So that you are sure to see execution.[Trust me, this helps debugging a lot and avoids many issues.]
The best thing would be, if those guys who implement the system would implement server-side UIA provider to their UI Elements!
But often that's not possible..., I used the following workaround (at least for clicking/toggling):
AutomationElement yourAE = ...// some code to find the right AutomationElement (AE)
clickablePoint = yourAE.GetClickablePoint();
also BoundingRectangleProperty could be of help
If you receive that clickable point you can use
System.Windows.Forms.Cursor.Position = new System.Drawing.Point((int)clickablePoint.X, (int)clickablePoint.Y);
to move to the location, and than click it via InputSimulator or some win32 (user32.dll) commands.
(note: of course you can also use InputSimulator or win32 to move the mouse - but I had some problems with the InputSimulator when it came to several screens with different locations or resolutions - so Cursor.Position was the easiest approach, which is also very reliable)

Alternative ContextMenuStrip

I would like to be able to change the style of the ContextMenuStrip currently available in .NET, I've always found it very ugly.
For example, this is the one in the Framework:
And I would like to use this system-style menu in my program:
Is there any way I can use the normal context strip in a managed app?
Try to use the old ContextMenu control, e.g.
ContextMenu menu = new ContextMenu();
menu.MenuItems.Add("Hello");
menu.MenuItems.Add("-"); // yes, this makes a separator !!!
menu.MenuItems.Add("World");
Image:

Silverlight business application initialize check

I am using the Business Silverlight application. I have incorporated some MVVM into this and were off an running with it. We are using some telerik controls, mostly the ribbon control and the docking. We register all the telerik ribbon controls in the about.xaml.cs file, the method is DisplayUI - its here where we register the docking control then we register the ribbon after this. What happens is that when you click the ABOUT link it shows our first tab with buttons(perfect). when you click the HOME link next to the ABOUT link, we go back to the home page..but when you click the ABOUT link again it registers the controls again so we end up with two tabs that are the same.
Is there a way to check to see if this about.xaml.cs file has already been initialized? Im guessing that is has a handle on the first call in memory as I am able to see the first tabs rendering..
Thanks
here is the about code
public About()
{
InitializeComponent();
DisplayUI();
this.Title = ApplicationStrings.AboutPageTitle;
}
that display UI does all the work in registering the dockpanel and the ribbons. We'd like to not have the DisplayUI() called if this has already been rendered once.
If you do it by event handler can you unsubscribe from the event at the end of the method? Without seeing some code it's hard to work out what to change.
It's not the nicest way of doing it, but if this code needs to run once and only once then you could have a static boolean variable on the class set to false and when you call DisplayUI you check the value of this. If it's false you set it to true and run the method, and if it's true you just return.

Categories