You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF弹窗控件及其内容右侧收缩调整方向问题求助

解决WPF自定义Popup右侧收缩与布局适配问题

问题概述

应用窗口移至屏幕右侧时,自定义Popup设置宽度后内容从左侧收缩截断,CustomPopupPlacementCallback未生效,需实现Popup从右侧收缩(内容保留左侧部分,超出宽度时截断右侧),同时不覆盖父Grid控件。

原XAML代码

<Popup>
<Border BorderThickness="0" Background="{DynamicResource RegularButtonBrush}" Padding="3,15,0,0" FlowDirection="LeftToRight">
  <StackPanel x:Name="popupSideMenuLabels" Orientation="Vertical" CanHorizontallyScroll="False" FlowDirection="LeftToRight">

    <TextBlock x:Name="tblogbook" Text="Loogout"/>
    <TextBlock x:Name="tblogbook" Text="Manage"/>
    <TextBlock x:Name="tblogbook" Text="Logbook"/>
    <TextBlock x:Name="tblogbook" Text="Notifications"/>
    <TextBlock x:Name="tblogbook" Text="Cell Settings"/>
    <TextBlock x:Name="tblogbook" Text="Reports"/>

  </StackPanel>
</Border>
</Popup>

原C#尺寸调整代码

var taskBarHeight = SystemParameters.PrimaryScreenHeight - SystemParameters.WorkArea.Height;
var screenHeight = SystemParameters.PrimaryScreenHeight - taskBarHeight;
var screenWidht = SystemParameters.PrimaryScreenWidth - 40; //40 pixels is width of parent
var gridPoint = sideMenuGrid.PointFromScreen(new Point(0, 0));

var gridSizeHeight = gridPoint.Y < 0
                        ? screenHeight - (-gridPoint.Y)
                        : screenHeight - gridPoint.Y;
var gridSizeWidth = gridPoint.X < 0
                    ? screenWidht - (-gridPoint.X)
                    : screenWidht - gridPoint.X;
mypopup.Height = gridSizeHeight;

if (DefaultSideMenuWidth - gridSizeWidth < 0) // Not at the edge of the screen
    sideMenuGrid.FindVisualChild<NonTopmostPopup>("PART_Popup").Width = DEFAULT_SIDE_MENU_WIDTH;
else // At the edge of the screen
{                    
    sideMenuGrid.FindVisualChild<NonTopmostPopup>("PART_Popup").Width = gridSizeWidth;
}

解决方案

1. 调整内容容器的截断与对齐逻辑

修改XAML,确保内容靠左对齐、文本从右侧截断,同时修正重复命名问题:

<Popup x:Name="mypopup" PlacementTarget="{Binding ElementName=sideMenuGrid}" Placement="Right">
    <Border BorderThickness="0" Background="{DynamicResource RegularButtonBrush}" Padding="3,15,3,0">
        <StackPanel x:Name="popupSideMenuLabels" Orientation="Vertical" HorizontalAlignment="Left">
            <TextBlock x:Name="tbLogout" Text="Logout" TextTrimming="CharacterEllipsis" HorizontalAlignment="Left"/>
            <TextBlock x:Name="tbManage" Text="Manage" TextTrimming="CharacterEllipsis" HorizontalAlignment="Left"/>
            <TextBlock x:Name="tbLogbook" Text="Logbook" TextTrimming="CharacterEllipsis" HorizontalAlignment="Left"/>
            <TextBlock x:Name="tbNotifications" Text="Notifications" TextTrimming="CharacterEllipsis" HorizontalAlignment="Left"/>
            <TextBlock x:Name="tbCellSettings" Text="Cell Settings" TextTrimming="CharacterEllipsis" HorizontalAlignment="Left"/>
            <TextBlock x:Name="tbReports" Text="Reports" TextTrimming="CharacterEllipsis" HorizontalAlignment="Left"/>
        </StackPanel>
    </Border>
</Popup>

2. 修复Popup位置与宽度计算逻辑

重新编写C#代码,正确计算可用空间并设置Popup位置,避免覆盖父Grid:

// 获取系统工作区(排除任务栏)
var workArea = SystemParameters.WorkArea;
// 获取父Grid在屏幕上的绝对位置
var gridScreenPos = sideMenuGrid.PointToScreen(new Point(0, 0));
// 获取父Grid的实际尺寸
var gridActualWidth = sideMenuGrid.ActualWidth;
var gridActualHeight = sideMenuGrid.ActualHeight;

// 计算Popup可用最大宽度:屏幕右边缘 - Grid右边缘
var availableWidth = workArea.Right - (gridScreenPos.X + gridActualWidth);
// 计算Popup可用最大高度:不超过Grid可见高度与屏幕剩余高度的最小值
var availableHeight = Math.Min(workArea.Bottom - gridScreenPos.Y, gridActualHeight);

// 设置Popup尺寸
mypopup.Height = availableHeight;
mypopup.Width = Math.Min(DEFAULT_SIDE_MENU_WIDTH, availableWidth);

// 绑定到父Grid并对齐右侧,确保不覆盖
mypopup.PlacementTarget = sideMenuGrid;
mypopup.Placement = PlacementMode.Right;
mypopup.HorizontalOffset = 0;

3. 让CustomPopupPlacementCallback生效

若需使用自定义布局回调,必须设置Placement="Custom",并在回调中基于父Grid尺寸计算位置:

mypopup.Placement = PlacementMode.Custom;
mypopup.CustomPopupPlacementCallback = (popupSize, targetSize, offset) =>
{
    // 对齐父Grid右侧,垂直居中
    return new[]
    {
        new CustomPopupPlacement(new Point(targetSize.Width, (targetSize.Height - popupSize.Height)/2), PopupPrimaryAxis.Horizontal)
    };
};

4. 适配父Grid部分可见场景

当父Grid仅显示一半时,需计算其实际可见区域:

var window = Window.GetWindow(sideMenuGrid);
var windowScreenPos = window.PointToScreen(new Point(0, 0));
// 计算Grid在窗口内的位置
var gridWindowPos = sideMenuGrid.TransformToAncestor(window).Transform(new Point(0, 0));
// 计算Grid在屏幕上的可见区域边界
var visibleGridRight = Math.Min(gridScreenPos.X + gridActualWidth, windowScreenPos.X + window.ActualWidth);
// 重新计算Popup可用宽度
availableWidth = workArea.Right - visibleGridRight;

内容的提问来源于stack exchange,提问作者Sid Brooklyn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 20:35:04