先上效果图:
思路:
- 制作带箭头的边框:使用Path
首先我们要制作带箭头,且有4个圆角的“边框”,简单点的可以去找个图片当背景,但是遇到复杂的就不适用了。所以这里我们选择使用Path 来画出这个带箭头圆角边框。 看下图(PPT画图好难)
我们分析一下这个边框形状,为了简单起见我们先假定长宽一样。
1、中间蓝色是个长宽=100的正方形,就是效果图中浅蓝色那部分,在该部分可以放任意多的内容。
2、假定4个圆角的半径都为5,箭头那里三角形底(黄色线),那就假定为2*r=10。
3、以左上角为坐标原点,应该不难算出图中所有绿色、红色点的坐标;以红色点为绘图起点,逆时针画图。
不难写出Path的代码,ArcSegment 和LineSegment 的Point 属性就是坐标值,其中ArcSegment 中的Size 属性可以设置弧度,也就是设置弧所在圆的半径。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <Path Stroke="Black" Margin="20"> <Path.Data> <PathGeometry> <PathFigure StartPoint="5,0" IsClosed="True"> <ArcSegment Point="0,5" Size="5,5" SweepDirection="Counterclockwise"/> <LineSegment Point="0,95"/> <ArcSegment Point="5,100" Size="5,5"/> <LineSegment Point="45,100"/> <LineSegment Point="50,105"/> <LineSegment Point="55,100"/> <LineSegment Point="95,100"/> <ArcSegment Point="100,95" Size="5,5"/> <LineSegment Point="100,5"/> <ArcSegment Point="95,0" Size="5,5" SweepDirection="Counterclockwise"/> </PathFigure> </PathGeometry> </Path.Data> </Path> |
结果:
2. 动态改变Path的大小
就如上述代码,Path的形状大小已经写死了,如何根据提示框中的内容,自动改变大小呢?显然不能将Path写在布局文件中,应该放在后台,动态添加Path。
后台代码很简单,就是把写死的宽度、高度、半径全部换成变量就好了,如我们写个返回类型是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | private PathGeometry GetPathGeometry(double width, double height, double r) {<!-- --> width += 2*r; height += 2*r; PathGeometry geometry = new PathGeometry(); PathFigure pathfigure = new PathFigure(); pathfigure.IsClosed = true; pathfigure.StartPoint = new Point(r, 0); pathfigure.Segments.Add(new ArcSegment(new Point(0, r), new Size(r, r), 0, false, SweepDirection.Counterclockwise, true)); pathfigure.Segments.Add(new LineSegment(new Point(0, height + r), true)); pathfigure.Segments.Add(new ArcSegment(new Point(r, height + 2*r), new Size(r, r), 0, false, SweepDirection.Counterclockwise, true)); pathfigure.Segments.Add(new LineSegment(new Point(width / 2, height + 2*r), true)); pathfigure.Segments.Add(new LineSegment(new Point(width / 2 + r, height + 3*r), true)); pathfigure.Segments.Add(new LineSegment(new Point(width / 2 + 2*r, height + 2*r), true)); pathfigure.Segments.Add(new LineSegment(new Point(width + r, height + 2*r), true)); pathfigure.Segments.Add(new ArcSegment(new Point(width + 2*r, height + r), new Size(r, r), 0, false, SweepDirection.Counterclockwise, true)); pathfigure.Segments.Add(new LineSegment(new Point(width + 2*r, r), true)); pathfigure.Segments.Add(new ArcSegment(new Point(width + r, 0), new Size(r, r), 0, false, SweepDirection.Counterclockwise, true)); geometry.Figures.Add(pathfigure); return geometry; } |
- 完整代码
布局文件
1 2 3 4 5 6 7 8 9 10 11 12 | <Button Name="btn" Content="测试popup提示框" Width="120" Height="50" Click="btn_Click" /> <Popup PlacementTarget="{Binding ElementName=btn}" Placement="Top" StaysOpen="False" IsOpen="False" AllowsTransparency="True" VerticalOffset="-2" Name="popup"> <Grid> <Path Name="path" Fill="#90000000" SnapsToDevicePixels="True"/> <Grid Name="popup_grid" Width="200" Height="100" Background="AliceBlue"> <!--该grid里面可以放任何东西--> <TextBlock Text="我是提示框" TextWrapping="Wrap"/> </Grid> </Grid> </Popup> |
按钮点击事件:
1 2 3 4 5 6 7 8 9 10 | private void btn_Click(object sender, RoutedEventArgs e) {<!-- --> if(popup.IsOpen == false) {<!-- --> popup.IsOpen = true; double r = 5; popup.HorizontalOffset = (popup_grid.ActualWidth + 2*r - btn.ActualWidth) / (-2); path.Data = GetPathGeometry(popup_grid.ActualWidth, popup_grid.ActualHeight, r); } } |
最后,记得调整Popup的
最后的最后,放一张我用的效果图: