Можно ли как-нибудь остановить всплывающее окно WPF, когда оно выходит за пределы экрана? - PullRequest
10 голосов
/ 08 января 2011

Можно ли как-нибудь остановить WPF всплывающее окно , когда он переходит за пределы экрана?

Я нашел этот старый вопрос , но он нене получить правильный ответ на это.Есть какой-либо способ сделать это?Я готов подкласс его, если это необходимо.Спасибо.

Ответы [ 5 ]

5 голосов
/ 08 января 2011

Как отмечает Андрей, это поведение глубоко внутри элемента управления Popup и его трудно преодолеть.Если вы хотите выполнить некоторую работу, это можно сделать, изменив размер и переведя содержимое всплывающего окна, когда оно достигнет краев экрана.В целях демонстрации мы сосредоточимся на левом краю экрана.

Если у нас есть какой-нибудь XAML, подобный этому:

<Window ...
        LocationChanged="Window_LocationChanged"
        SizeChanged="Window_SizeChanged"
        >
    <Grid>
        <Rectangle Name="rectangle1" Width="100" Height="100" Fill="Blue"/>
        <Popup Name="popup1" PlacementTarget="{Binding ElementName=rectangle1}" IsOpen="True" Width="100" Height="100">
            <TextBlock Background="White" TextWrapping="Wrap" Width="100" Height="100">
                <TextBlock.Text>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</TextBlock.Text>
            </TextBlock>
        </Popup>
    </Grid>
</Window>

и выделенный код, подобный этому:

private void Window_LocationChanged(object sender, EventArgs e)
{
    RefreshPopupPosition();
}

private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
    RefreshPopupPosition();
}

private void RefreshPopupPosition()
{
    var upperLeft = rectangle1.PointToScreen(new Point(0, 100));
    var xOffset = Math.Min(0, upperLeft.X);
    popup1.Width = xOffset + 100;
    (popup1.Child as FrameworkElement).Margin = new Thickness(xOffset, 0, 0, 0);
    popup1.HorizontalOffset += 1;
    popup1.HorizontalOffset -= 1;
}

затем, рассчитав, что Popup будет за кадром, мы можем уменьшить ширину контента и дать ему отрицательное поле, чтобы отображаемая на экране часть была обрезана до того, что было быпоявились, если бы Popup позволили это сделать.

Это должно быть расширено, чтобы охватить все четыре края экрана и возможность использования нескольких экранов, но это демонстрирует, что подход является работоспособным.

1 голос
/ 09 мая 2017

в wpf нет способа вывести Popup из экрана, но вы можете принудительно установить позицию всплывающего окна, вызвав "SetWindowPos" через p / invoke:

#region P/Invoke imports & definitions

        private const int HWND_TOPMOST = -1;
        private const int HWND_NOTOPMOST = -2;
        private const int HWND_BOTTOM = 1;
        private const int SWP_NOMOVE = 0x0002;
        private const int SWP_NOSIZE = 0x0001;
        private const int SWP_NOACTIVATE = 0x0010;
        private const int GW_HWNDPREV = 3;
        private const int GW_HWNDLAST = 1;


  [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
        private static extern int SetWindowPos(IntPtr hWnd, int hwndInsertAfter, int x, int y, int cx, int cy, int wFlags); 

 #endregion

 private void updateposition(Item item)
        {
            if (item.IsOpen)
            {
                IntPtr hwnd = ((HwndSource)PresentationSource.FromVisual(item.popup.Child)).Handle;
                SetWindowPos(hwnd, 0, (int)item.WorkPoint.X, (int)item.WorkPoint.Y, (int)item.popup.Width, (int)item.popup.Height, SWP_NOSIZE | SWP_NOACTIVATE);

            }


        }
1 голос
/ 08 января 2011

Я не думаю, что есть способ сделать это.По крайней мере, чистый способ.Если вы загляните в класс Popup с помощью Reflector, вы найдете метод UpdatePosition, который будет корректировать расположение всплывающего окна таким образом, чтобы оно оставалось между границами экрана.Этот метод вызывается из нескольких мест, из On***Changed обратных вызовов (OnPlacementChanged, OnVerticalOffsetChanged и т. Д.).

Если вы действительно действительно хотите получить эту функциональность, у вас может быть небольшой шансрасширить класс Popup, переопределить некоторые метаданные в свойствах, которые зарегистрированы с помощью обратных вызовов On***Changed, чтобы UpdatePosition никогда не вызывался, однако большинство людей посчитают это чистым злом, я тоже не рекомендую.

0 голосов
/ 19 июля 2016

Вы должны поместить всплывающее окно и его цель внутри панели Canvas, чтобы оно не перемещалось из-за проблемы с краем экрана при управлении всплывающими окнами.

          <Canvas>
            <Rectangle Name="rectPopUp" Width="30" Height="30"/>
            <Button Width="20" Height="20" Name="btnAppLauncher" Click="btnAppLauncher_Click" Margin="-5,-2,0,0">
                <Button.Content>
                    <Path Fill="White" Stretch="Uniform" Data="M16,20H20V16H16M16,14H20V10H16M10,8H14V4H10M16,8H20V4H16M10,14H14V10H10M4,14H8V10H4M4,20H8V16H4M10,20H14V16H10M4,8H8V4H4V8Z"></Path>
                </Button.Content>
            </Button>
            <Popup Name="pnlAppLauncherPopup"  PlacementRectangle="0,25,0,0" PlacementTarget="{Binding ElementName=btnAppLauncher}" Placement="Bottom" AllowsTransparency="True" PopupAnimation="Slide">
                <UniformGrid Name="pnlAppLauncher">
                </UniformGrid>
            </Popup>
        </Canvas>

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

0 голосов
/ 02 января 2015

Вы можете использовать PrecisePopup элемент управления из моей библиотеки с открытым исходным кодом JungleControls .Он будет располагать всплывающее окно точно так, как указано, даже если это означает, что оно частично за пределами экрана.

Он может автоматически выбирать наиболее подходящее место размещения среди определенных мест размещения, но если вам просто нужно одно точное размещение всплывающего окначто соответствует расположению «снизу» встроенного всплывающего окна, вы можете сделать это так:

<jc:PrecisePopup PlacementTarget="{Binding ElementName=SomeTarget}"
                 IsOpen="{Binding IsOpen}">
    <jc:PrecisePopup.Placements>
        <jc:PrecisePopupPlacement VerticalTargetAlignment="Bottom" />
    </jc:PrecisePopup.Placements>
    <!-- Popup content here... -->
</jc:PrecisePopup>
...