Hi,
How would I go about replacing the stock rollover tooltip for my own WPF user control whenever a certain type of object is hovered over?
Is it even possible?
Thanks
Solved! Go to Solution.
Solved by Keith.Brown. Go to Solution.
sorry about this mis interpretation.
For tooltips on objects i'll (mis) use hyperlinks for that purpose, like in this pseudo code
using (HyperLinkCollection hyperlinks = TheEntity.Hyperlinks)
{
using (HyperLink newHyperLink = new HyperLink())
{
newHyperLink.Description = "Some Description";
newHyperLink.Name = "Some Name";
newHyperLink.SubLocation = "Some Description";
hyperlinks.Add(newHyperLink);
}
}
Yes, you can.
First you need to add two event handlers to your code. These should be added to every open document and to each newly opened/created document.
ComponentManager.ToolTipOpened += ComponentManager_ToolTipOpened; document.Editor.PointMonitor += Editor_PointMonitor;
In the point monitor event handler you should monitor the object being hovered over and determine if it is the object that you wish to display the tooltip for. In the code below I am looking at AutoCAD MEP objects to determine if they need to display a custom tooltip.
private static ObjectId toolTipObjectId = ObjectId.Null; public static void PointMonitor(object sender, PointMonitorEventArgs e) { toolTipObjectId = ObjectId.Null; if (Application.GetSystemVariable("RollOverTips").ToString() != "1" || !SuperToolTipSettings.EnableSuperToolTips) return; if ((e.Context.History & PointHistoryBits.FromKeyboard) == PointHistoryBits.FromKeyboard) return; FullSubentityPath[] paths = e.Context.GetPickedEntities(); if (paths == null || paths.Length == 0) return; ObjectId[] ids = paths[0].GetObjectIds(); if (ids == null || ids.Length == 0) return; var i = 0; if (!ids[i].IsValid) return; GetClass(ids, i) ; } private static void GetClass(ObjectId[] ids, int i) { if ((ids[i].ObjectClass.Name == "AecbDbDuct") || (ids[i].ObjectClass.Name == "AecbDbDuctFitting") || (ids[i].ObjectClass.Name == "AecbDbDuctCustomFitting") || (ids[i].ObjectClass.Name == "AecbDbDuctFlex") || (ids[i].ObjectClass.Name == "AecbDbPipe") || (ids[i].ObjectClass.Name == "AecbDbPipeFitting") && SuperToolTipSettings.DisplayPipeFittings) || (ids[i].ObjectClass.Name == "AecbDbPipeCustomFitting") || (ids[i].ObjectClass.Name == "AecbDbPipeFlex") && SuperToolTipSettings.DisplayFlexPipe) || (ids[i].ObjectClass.Name == "AecbDbCableTray" && SuperToolTipSettings.DisplayCableTray) || (ids[i].ObjectClass.Name == "AecbDbCableTrayFitting") || (ids[i].ObjectClass.Name == "AecbDbConduit") || (ids[i].ObjectClass.Name == "AecbDbConduitFitting" && SuperToolTipSettings.DisplayConduitFittings) || (ids[i].ObjectClass.Name == "AecbDbSchematicPipe") || (ids[i].ObjectClass.Name == "AecbDbSchematicPipeFitting") || (ids[i].ObjectClass.Name == "AecbDbSchematic") || (ids[i].ObjectClass.Name == "AecbDbSchematicSymbol") || (ids[i].ObjectClass.Name == "AecbDbDevice") || (ids[i].ObjectClass.Name == "AecbDbPanel") || (ids[i].ObjectClass.Name == "AecbDbWire") || (ids[i].ObjectClass.Name == "AecbDbMvPart")) { toolTipObjectId = ids[i]; } if (ids[i].ObjectClass.Name == "AcDbBlockReference") { GetClass(ids, i + 1); } }
The code above is recursive and will delve into block references and xrefs to find the object and store the objectID of the object being hovered over.
Once you have the objectId of a object you wish to display a new tooltip for you will need to display the tooltip. The code in the tooltipopened event handler takes care of this.
public static void ComponentManager_ToolTipOpened(object sender, EventArgs e) { if (toolTipObjectId != ObjectId.Null && Application.GetSystemVariable("RollOverTips").ToString() == "1") { var toolTip = sender as ToolTip; // This check is needed to distinguish between the ribbon tooltips and the entity tooltips if (toolTip != null) { Member member = null; using (Transaction transaction = HostApplicationServices.WorkingDatabase.TransactionManager.StartOpenCloseTransaction()) { member = transaction.GetObject(toolTipObjectId, 0) as Member; transaction.Commit(); } if (member != null) { var memberToolTip = new SuperToolTipDisplay { MaxWidth = 600, ClassName = {Text = "Object Type"} }; // Repeat this section for each property of the object to add to the tooltip
// I added generic text for this sample but you would instead get properties from the object
// and display them here. The blockName would be the name of the property and the blockValue
// would be the value of the property. { var blockName = new TextBlock(); var blockValue = new TextBlock(); blockName.Text = "Property Name"; blockName.Margin = new Thickness(0.0, 5.0, 0.0, 0.0); blockName.HorizontalAlignment = HorizontalAlignment.Left; blockName.VerticalAlignment = VerticalAlignment.Center; blockValue.Text = "Property Value"; blockValue.Margin = new Thickness(10.0, 5.0, 10.0, 0.0); blockValue.TextWrapping = TextWrapping.Wrap; blockValue.HorizontalAlignment = HorizontalAlignment.Left; blockValue.VerticalAlignment = VerticalAlignment.Center; memberToolTip.StackPanelName.Children.Add(blockName); memberToolTip.StackPanelValue.Children.Add(blockValue); // Because BlockValue textblock can have wrapped text we need to set the height // of the BlockName textblock to equal that of the BlockValue textblock. // We need to give the wpf layout engine time to calculate the actual height // so that we can set the values. memberToolTip.StackPanelValue.Dispatcher.BeginInvoke( DispatcherPriority.Background, new DispatcherOperationCallback(delegate { blockName.Height = blockValue.ActualHeight; return null; }), null); } // Swap out the AutoCAD ToolTip with our own ToolTip toolTip.Content = memberToolTip; member.Dispose(); } } // Reset the object for the next tooltip toolTipObjectId = ObjectId.Null; }
The xaml for the wpf user control to replace the tooltip.
<UserControl x:Class="SuperToolTipDisplay" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"> <Grid x:Name="RootGrid" HorizontalAlignment="Left" VerticalAlignment="Top"> <TextBlock x:Name="ClassName" TextWrapping="Wrap" Text="TextBlock" Margin ="10,10,10,10" FontWeight="Bold" HorizontalAlignment="Left" VerticalAlignment="Top"/> <DockPanel x:Name="LineContainer" HorizontalAlignment="Left" Margin="10,30,10,10" VerticalAlignment="Top"> <StackPanel x:Name="StackPanelName" Orientation="Vertical" VerticalAlignment="Top" MaxWidth="290"/> <WrapPanel x:Name="StackPanelValue" Orientation="Vertical" VerticalAlignment="Top" /> </DockPanel> </Grid> </UserControl>
That should be enough to get you going. I grabbed the code out of an active project and think that I got everything.
In summary, you check the object being hovered over to get its objectId and check that objectid againt a list of objects you are monitoring. Then once the tooltip for that object is opened check to see if it is a object that we want and then replace the tooltip panel with one of our own creation. I have been unsuccessful in adding an image to the tooltip but I believe it is possible.
See this link. http://stackoverflow.com/questions/10873263/autocad-infobox-functionality
I have been using this code for a couple years to display custom tooltips and it works extremely well and extremely fast. I need to spend some time and come back to this code and "adjust" it to be able to display an image in the tooltip. Let me know if you have any issues with it and I will create a sample project that will show the complete code.
Keith,
Inspired by the discussion here and your code, I post an article here. Do you still have issue of displaying image in tool tip? It seems I do not have problem showing image here. The picture used in my code is PNG with size of over 1MB, which could be considered "fairly big" for tool tip.
Norman Yuan
Hi Norman,
Nice write up and thanks for the shout out!
I was able to finally get an image to display. At the time it was my lack of understanding of WPF that caused the issue but eventually I did something very similar to your code where you are converting the image to get it to work.
Can't find what you're looking for? Ask the community or share your knowledge.