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
相关产品推荐
相关产品推荐

