This is a really cool little sample put together by Philippe Leefsma, from our DevTech team in Europe, with the help of George Varghese from the AutoCAD Engineering team. Thanks, Philippe and George! :-)
This question came up, recently: an ADN member wanted to be able to add an editable textbox to the ribbon inside AutoCAD and then be notified of the data entered into it, as well as being notified when the control gained and lost focus.
Here’s some simple C# code that does just this:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Autodesk.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows;
using System;
namespace NotifyingRibbonTextbox
{
public class Commands
{
public bool _added = false;
[CommandMethod("RTB")]
public void RibbonTextBox()
{
if (!_added)
{
// Look for the standard "Plug-ins" tab
RibbonControl rc = ComponentManager.Ribbon;
RibbonTab rt = null;
foreach (RibbonTab tab in rc.Tabs)
{
if (tab.AutomationName == "Plug-ins")
{
rt = tab;
break;
}
}
// If we didn't find it, create a custom tab
if (rt == null)
{
rt = new RibbonTab();
rt.Title = "Custom";
rt.Id = "ID_CUSTOMRIBBONTAB";
rc.Tabs.Add(rt);
}
// Create our custom panel, add it to the ribbon tab
RibbonPanelSource rps = new RibbonPanelSource();
rps.Title = "Notifying Textbox";
RibbonPanel rp = new RibbonPanel();
rp.Source = rps;
rt.Panels.Add(rp);
// Create our custom textbox, add it to the panel
NotifyingTextBox tb = new NotifyingTextBox(150);
tb.IsEmptyTextValid = false;
tb.AcceptTextOnLostFocus = true;
tb.InvokesCommand = true;
tb.CommandHandler = new TextboxCommandHandler();
rps.Items.Add(tb);
// Set our tab to be active
rt.IsActive = true;
// We only want to add it once, so set a flag
_added = true;
}
}
public static void Print(string s)
{
// A simple helper to write to the command-line
Document doc =
Autodesk.AutoCAD.ApplicationServices.
Application.DocumentManager.MdiActiveDocument;
doc.Editor.WriteMessage(s);
}
}
public class TextboxCommandHandler : ICommand
{
#pragma warning disable 67
public event EventHandler CanExecuteChanged;
#pragma warning restore 67
public bool CanExecute(object parameter)
{
// Yes, we can execute
return true;
}
public void Execute(object parameter)
{
// Dump the textbox contents to the command-line
NotifyingTextBox tb = parameter as NotifyingTextBox;
if (tb != null)
{
Commands.Print(
"\nRibbon Textbox: " +
tb.TextValue + "\n"
);
tb.ClearText();
}
}
}
public class NotifyingTextBox : RibbonTextBox
{
public NotifyingTextBox(double width)
{
Width = width;
MinWidth = width;
// Register our focus-related event handlers
EventManager.RegisterClassHandler(
typeof(TextBox), TextBox.GotKeyboardFocusEvent,
new RoutedEventHandler(OnGotFocus)
);
EventManager.RegisterClassHandler(
typeof(TextBox), TextBox.LostKeyboardFocusEvent,
new RoutedEventHandler(OnLostFocus)
);
}
public void ClearText()
{
TextValue = "";
}
// Both events call the same helper, with a custom message
private void OnGotFocus(object sender, RoutedEventArgs e)
{
OnFocusChange(sender, e, "\nTextbox got focus :)\n");
}
private void OnLostFocus(object sender, RoutedEventArgs e)
{
OnFocusChange(sender, e, "\nTextbox lost focus :(\n");
}
// Our helper function to print a message only when
// our custom textbox exists
private void OnFocusChange(
object sender, RoutedEventArgs e, string msg
)
{
if (e != null && e.Source != null)
{
TextBox tb = e.Source as TextBox;
if (tb != null)
{
NotifyingTextBox mtb =
tb.DataContext as NotifyingTextBox;
if (mtb != null)
{
Commands.Print(msg);
}
}
}
}
}
}
There are a few points worth noting about this implementation:
- We register event handlers to check when our custom NotifyingTextBox receives or loses focus.
- These both call the same helper function, to avoid duplicated code.
- We attach a "command handler" that notifies us when the user hits enter after typing a string.
- It's important to set the IsEmptyTextValid flag to false if we want to stop empty “commands” from coming through (this doesn’t stop the TextBox from being empty, just from it calling through to Execute() when it is).
- During the Execute() method of the handler, we extract the TextValue from the NotifyingTextBox before clearing it.
Let’s see what happens when you build this code into a .NET assembly, NETLOAD it and execute the RTB command. Firstly, it adds a new control to the “Plug-ins” tab, if it’s found (otherwise it will create its own “Custom” tab):
As we set focus to that control and set it back elsewhere, we see messages printed to the command-line:
Command: RTB
Command:
Textbox got focus :)
Textbox lost focus :(
As we enter text into the custom textbox, and hit return:
We see the text echoed to the command-line, too:
Ribbon Textbox: This is a message from Kean
That's it for today’s post. Next time we'll extend this implementation to auto-resize as text is entered into the box.