Search code examples
wpfdata-bindingpopup

Placing a PopUp to the top of the mouse-cursor position


I am working on an interactive chart, where I am displaying a popup with more information, when the user clicks on a data-point.This works fine so far and this is the popup definition:

<Popup IsOpen="{Binding PopupViewModel.IsOpen}"
        Placement="Mouse"
        HorizontalOffset="-150">
    <Popup.Resources>
        <DataTemplate DataType="{x:Type ViewModels:DataPointPopUpContentViewModel}">
            <Views:DataPointPopUpContentView/>
        </DataTemplate>
    </Popup.Resources>
    <Border BorderThickness="1" BorderBrush="Black" Background="White">
        <ContentPresenter Content="{Binding PopupViewModel}" />
    </Border>
</Popup>

The default placement of the popup, when using Placement="Mouse" is at the bottom right of the mouse-cursor. However I want the popup to be placed just at the top edge the mouse-cursor. As you can see I have achieved the horizontal centering by setting HorizontalOffset="-150", which is have of the fixed popup-width (Width=300). For the vertical placement I have the problem, that the popup-height is not fixed, since I am displaying an image of variable size and aspect-ratio inside it. I have therefore tried to set VerticalOffset to the ActualHeight of the pupup by adding VerticalOffset="{Binding ActualHeight}". This does not work unfortunately. Any ideas on what I am doing wrong and how to achieve my goal?


Solution

  • First of all you need a converter:

    public class MultiplyConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is double && parameter is double)
            {
                return ((double)value) * ((double)parameter);
            }
    
            return value;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    }
    

    Then try to bind the VerticalOffset property to the ActualHeight of the Popup's child:

    <Window.Resources>
        <local:MultiplyConverter x:Key="MultiplyConverter" />
        <sys:Double x:Key="Factor">-.5</sys:Double>
    </Window.Resources>
    
    <Popup IsOpen="{Binding PopupViewModel.IsOpen}"
            Placement="Mouse"
            HorizontalOffset="-150">
        <Popup.VerticalOffset>
            <Binding Path="Child.ActualHeight" RelativeSource="{RelativeSource Self}"
                        Converter="{StaticResource MultiplyConverter}" ConverterParameter="{StaticResource Factor}" />
        </Popup.VerticalOffset>
    
    
        <!-- popup content -->
    </Popup>
    

    I hope it can help you.