0
votes

I've tried several different solutions to this, but can't land on one that meets all of my needs.

We have an observable collection of objects that each have a status and a name. It's a sort of task-list of running items. To display this list in WPF, we have some code that represents each item as an ellipse with some colors and animations.

The problem is that we want to display the name of the item as a 'popup' both on mouseover, or when the task is in a given state.


Attempt #1

My first attempt implemented this as a Datatemplate (to be used as an ItemTemplate) with an actual WPF Popup. I implemented two datatriggers - one for mouseover and one for task state. I positioned the popup based on my ellipse and everything was great. However, moving the window or switching to a different window left the popup on top of everything.


Attempt #2

Instead of using the popup I used a textbox in a canvas. This works great until the Datatemplate is used in the Listbox. The item host (stackpanel) ends up clipping the string.

Here's example code:

<DataTemplate x:Key="EllipseTemplate">
    <Grid Height="40" Width="40">
        <Canvas Name="PopupCanvas" HorizontalAlignment="Center" Width="500">
            <TextBlock Name="PopupName"
                   Width="{Binding ElementName=PopupCanvas, Path=ActualWidth}"
                   Text="{Binding}"
                   Background="Transparent"
                   FontSize="16" HorizontalAlignment="Center" TextAlignment="Center" FontWeight="Bold" 
                   Canvas.Top="-25"
                   Visibility="Collapsed"
                   />
        </Canvas>
        <Ellipse x:Name="Ellipse" Height="25" Width="25" Margin="0"
                 HorizontalAlignment="Center" VerticalAlignment="Center"
                 Fill="Green" 
                 RenderTransformOrigin="0.5, 0.5" StrokeThickness="0.5" Stroke="Black">
        </Ellipse>
    </Grid>
    <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource TemplatedParent}}" Value="True">
            <Setter TargetName="PopupName" Property="Visibility" Value="Visible" />
        </DataTrigger>
    </DataTemplate.Triggers>
</DataTemplate>

<Grid Name="Test" Background="LightGoldenrodYellow" ClipToBounds="False" Margin="50">
    <ListBox Name="OverlayTest" 
             Background="CornflowerBlue" 
             BorderThickness="0" 
             VerticalAlignment="Center" 
             Margin="10" 
             ClipToBounds="False" 
             ItemTemplate="{StaticResource EllipseTemplate}">
        <sys:String>Very long string that will get clipped</sys:String>
        <sys:String>Two</sys:String>
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal" IsItemsHost="True" Margin="10,50,10,50" ClipToBounds="False"/>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
    </ListBox>
</Grid>

Example of clipping


Attempt #3

I moved my canvas/textbox outside of the datatemplate and create a grid to put it above the listbox of ellipses. This works from a layout perspective, but creates a big mess in terms of checking for mouseover and centering the textbox on the control that's active/hovered.


So that leaves me without an implementation that works the way I want. Anyone have any suggestions?

2

2 Answers

0
votes

Ok here I have another idea. I had problem with the ListBox before. Try replacing the ListBox with an ItemsControl.

0
votes

Attempt #2 sounds like is working fine. You should be able to solve the issue of the clipping using one of these solutions (or all of them):

  1. Set the ClipToBounds property of the ListBox to false
  2. Set the ClipToBounds property of the Stackpanel to false