Управление всплывающим окном перемещается с родительским

Надеюсь, это быстрый для вас экспертов WPF. Есть ли простое решение XAML, позволяющее моему всплывающему меню перемещаться, когда вдова перемещается или меняет размер? Код ниже. Если нет, я всегда могу обработать событие в коде.

<Grid>
    <Canvas>
        <Expander Header="details" HorizontalAlignment="Center" VerticalAlignment="Top" ExpandDirection="Down"
                  Expanded="Expander_Expanded" Panel.ZIndex="99" Collapsed="Expander_Collapsed" Name="expander">

                <Popup PopupAnimation="Slide" Name="popup" Width="200" Height="200" StaysOpen="True" AllowsTransparency="True" 
                       IsOpen="False" >
                <Grid Background="Cornsilk">
                    <Grid.BitmapEffect>
                        <DropShadowBitmapEffect/>
                    </Grid.BitmapEffect>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                    </Grid.RowDefinitions>
                   <TextBlock TextWrapping="Wrap" FontWeight="Bold">
                      Some example text
                   </TextBlock>
                </Grid>
            </Popup>

        </Expander>
    </Canvas>
</Grid>

Ответ 1

Здесь решение с использованием:

Этот образец только для разметки состоит из текстового поля и всплывающего окна. Всплывающее окно открывается, когда текстовое поле сфокусировано. Всплывающее окно следует за окном, когда оно перемещается, перехватывая событие изменения местоположения окна и заставляя всплывающее окно соответствующим образом перемещаться.

<Grid>
    <StackPanel>
        <TextBox x:Name="textBox1" Width="200" Height="20"/>
        <Popup PlacementTarget="{Binding ElementName=textBox1}" IsOpen="{Binding IsKeyboardFocused, ElementName=textBox1, Mode=OneWay}">
            <TextBlock Background="White" Text="Sample Popup content."/>
            <p:Attached.Operations>
                <p:EventHandler Path="Loaded">
                    <p:ScriptHandler Path="@FindAncestor([Window], @AssociatedObject.PlacementTarget).LocationChanged">
                        @AssociatedObject.HorizontalOffset += 1;
                        @AssociatedObject.HorizontalOffset -= 1;
                    </p:ScriptHandler>
                </p:EventHandler>
            </p:Attached.Operations>
        </Popup>
    </StackPanel>
</Grid>

Ответ 2

Это в значительной степени ответ Рика, но в коде, потому что я не вижу абсолютно никаких причин для введения другой зависимости.

protected override void OnLocationChanged(EventArgs e)
{
    popup.HorizontalOffset += 1;
    popup.HorizontalOffset -= 1;
    base.OnLocationChanged(e);
}

Просто скопируйте и вставьте в свой код код и замените идентификатор popup на один из ваших идентификаторов экземпляра всплывающего окна.


Я нахожу его намного лучше, он более краткий, он не использует события, которые вам придется либо отменить подписку, либо утечку памяти.
И для вашей среды выполнения приложения переопределение будет иметь лучшие результаты (ничто не заметное, но иррационалисты с микроэффективностью, например, по-вашему, все равно будут просто любить его).