- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
上一篇文章写了如何创建自定义窗体:使用 WindowChrome 或者 WindowStyle=“None”这两种方式。本文将讲述如何设置窗体的效果(以阴影效果为例),以及在效果模式下,窗体各功能的配合.
窗体的范围,就是白色区域部分:包括窗体的边框,标题栏,以及内部的空白部分。出了白色范围,不再属于窗体,且窗体也不能影响到白色区域意外的地方。理解这一点很重要! 。
要设置透明窗体,比较简单,要同时设置三个属性:
<Window x:Class="ControlTest.EffectNoneWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ControlTest"
mc:Ignorable="d"
Title="EffectNoneWindow" Height="450" Width="800"
AllowsTransparency="True" Background="Transparent" WindowStyle ="None"
>
<Grid>
</Grid>
</Window>
注意:当AllowTransparency = “True”时,WindowStyle的值必须为None.
这个截图就是窗体。因为它是透明的,所以直接看到了桌面(注意看顶部的调试工具条).
<Window x:Class="ControlTest.EffectNoneWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:ControlTest" mc:Ignorable="d" Title="EffectNoneWindow" Height="450" Width="800" AllowsTransparency="True" Background="Transparent" WindowStyle ="None"> <Border Margin="20" Background="White" > <Border.Effect> <DropShadowEffect Direction="0" BlurRadius="20" ShadowDepth="0" Color="#FF585252" /> </Border.Effect> </Border> </Window>
注意,最外圈的灰色部分(图中标1的地方)是桌面(它是微信截图的时候产生的);图中标2的青色框,是窗体的实际边框,它与白色部分(图中标3的地方)之间的空间,就是Border的Margin。为什么要这个Margin?
因为Border有一个Effect。如果没有这个Margin,Effect没有地方放置(因为任何窗体的效果、元素,都不能超出窗体的区域).
你以为到这里文章就结束了?No No No,让我们添加功能之后再看看。把上一篇文章中,关于标题栏,按钮的功能加上.
Xaml代码: <Window x:Class= " ControlTest.EffectNoneWindow " xmlns = " http://schemas.microsoft.com/winfx/2006/xaml/presentation " xmlns:x = " http://schemas.microsoft.com/winfx/2006/xaml " xmlns:d = " http://schemas.microsoft.com/expression/blend/2008 " xmlns:mc = " http://schemas.openxmlformats.org/markup-compatibility/2006 " xmlns:local = " clr-namespace:ControlTest " mc:Ignorable = " d " Title = " EffectNoneWindow " Height= " 450 " Width= " 800 " AllowsTransparency = " True " Background= " Transparent " WindowStyle = " None " > <Border Margin= " 20 " Background= " White " > <Border.Effect> <DropShadowEffect Direction= " 0 " BlurRadius= " 20 " ShadowDepth= " 0 " Color= " #FF585252 " /> </Border.Effect> <Grid> <Grid.RowDefinitions> <RowDefinition Height= " auto " /> <RowDefinition Height= " * " /> </Grid.RowDefinitions> <Border Height= " 30 " Background= " YellowGreen " MouseDown = " TitleMove " > <Grid> <Grid.Resources> <Style TargetType= " Button " > <Setter Property= " Width " Value= " 30 " /> <Setter Property= " Background " Value= " Transparent " /> <Setter Property= " BorderThickness " Value= " 0 " /> </Style> </Grid.Resources> <StackPanel Orientation= " Horizontal " WindowChrome.IsHitTestVisibleInChrome= " True " > <Image /> <TextBlock VerticalAlignment= " Center " Margin= " 3,0 " Text= " {Binding Title, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}} " /> </StackPanel> <StackPanel Orientation= " Horizontal " HorizontalAlignment= " Right " WindowChrome.IsHitTestVisibleInChrome= " True " > <Button Content= " _ " Click= " Btn_Min " /> <Button Content= " Max " Click= " Btn_Max " /> <Button Content= " X " Click= " Btn_Close " /> </StackPanel> </Grid> </Border> <TabControl Grid.Row= " 1 " Margin= " 10 " > <TabItem Header= " 项目 " /> <TabItem Header= " 代码 " /> </TabControl> </Grid> </Border> </Window> C#代码:( 此处不包含调整窗体大小的代码。具体请看上一篇文章的末尾 ) // 窗体移动 private void TitleMove( object sender, MouseButtonEventArgs e) { if (e.ChangedButton != MouseButton.Left) return ; // 非左键点击,退出 if (e.ClickCount == 1 ) { this .DragMove(); // 拖动窗体 } else { WindowMax(); // 双击时,最大化或者还原窗体 } } // 最小化 private void Btn_Min( object sender, RoutedEventArgs e) { this .WindowState = WindowState.Minimized; } // 关闭窗体 private void Btn_Close( object sender, RoutedEventArgs e) { this .Close(); } // 最大化、还原 private void Btn_Max( object sender, RoutedEventArgs e) { WindowMax(); } private void WindowMax() { if ( this .WindowState == WindowState.Normal) { this .WindowState = WindowState.Maximized; } else { this .WindowState = WindowState.Normal; } }
大部分功能完好。可以用鼠标在标题上拖动窗体,双击标题栏放大、缩小,最小化、关闭按钮工作正常。唯独最大化按钮的效果不是我们想要的! 。
问题:1. 最大化之后,它的四周与屏幕边缘还有空白;2. 它遮住了桌面的任务栏.
这才是要解决的问题的关键!这个问题的产生,还是“窗体的空间范围”引起的:
1. 因为最大化的是窗体,而窗体包括了最外层Border的Margin,所以最大化之后,Margin依然是存在的,四周与屏幕之间自然就有了空白.
2. 因为没有操作系统赋予的“窗口边框”,窗体也就不知道了屏幕可用范围大小,只能是尽可能占据全部屏幕,因此就遮住了桌面的任务栏.
要解决这两个问题,只需要做两个设置。且看如下代码(最重要的是OnStateChanged()方法):
Xaml代码: <!-- 设置最外层Border的Name属性 --> <Border Name="bd" Margin= " 20 " Background= " White " > …… </Border> C#代码: public partial class EffectNoneWindow : Window { Thickness originMargin; // 记录bd的初始Margin值 Thickness zeroMargin = new Thickness( 5 ); // 设置当窗体最大化之后,bd的Margin值。该值本应该为0,但是实际上最大化之后会有点“吃”窗体,因此设置为5或者其他数值,以求更好的视觉效果。 public EffectNoneWindow() { InitializeComponent();
// 注册事件。如此当拖动鼠标到屏幕的边缘时,Windows系统会将窗体最大化,程序也能正常工作。 this .StateChanged += OnStateChanged; // 设置窗体最大化时的最大高度 this .MaxHeight = SystemParameters.MaximizedPrimaryScreenHeight; this .originMargin = this .bd.Margin; } private void OnStateChanged(object? sender, EventArgs e) { if ( this .WindowState == WindowState.Normal) { // Normal状态时,将bd的Margin设置为初始值 this .bd.Margin = this .originMargin; } else { // 最大化时,将bd的Margin设置为0; this .bd.Margin = zeroMargin; } } // 窗体移动 private void TitleMove( object sender, MouseButtonEventArgs e) { if (e.ChangedButton != MouseButton.Left) return ; // 非左键点击,退出 if (e.ClickCount == 1 ) { this .DragMove(); // 拖动窗体 } else { WindowMax(); // 双击时,最大化或者还原窗体 } } // 最小化 private void Btn_Min( object sender, RoutedEventArgs e) { this .WindowState = WindowState.Minimized; } // 关闭窗体 private void Btn_Close( object sender, RoutedEventArgs e) { this .Close(); } // 最大化、还原 private void Btn_Max( object sender, RoutedEventArgs e) { WindowMax(); } private void WindowMax() { if ( this .WindowState == WindowState.Normal) { this .WindowState = WindowState.Maximized; } else { this .WindowState = WindowState.Normal; } } }
你以为这就完事了?太天真了,微软的东西哪有这么简单?它总是会给你埋坑的! 。
以上代码,在点击“最大化”按钮、用鼠标把窗体拖到屏幕顶端(系统赋予的最大化操作)时,都OK,没问题。但如果把窗体用鼠标拖到屏幕的左侧、右侧、屏幕的四个角时,系统会让窗体占据部分屏幕(类似于分屏)时,窗体呈现的效果如下:
窗体高度OK了,但是Margin错了! 。
因此,还要修改。代码如下:
public partial class EffectNoneWindow : Window { Thickness originMargin; Thickness margin5 = new Thickness( 8 ); Thickness marginTopLeft; Thickness marginTopRight; Thickness marginBottomLeft; Thickness marginBottomRight; Thickness marginLeft; Thickness marginRight; double maxWidth = SystemParameters.MaximizedPrimaryScreenWidth; double maxHeight = SystemParameters.MaximizedPrimaryScreenHeight; public EffectNoneWindow() { InitializeComponent(); // 不再使用StateChanged事件,而使用SizeChanged事件 this.SizeChanged += EffectNoneWindow_SizeChanged; // 设置窗体最大化时的最大高度 MaxHeight = maxHeight; originMargin = bd.Margin; marginTopLeft = new Thickness( 0 , 0 , originMargin.Right, originMargin.Bottom); marginTopRight = new Thickness(originMargin.Left, 0 , 0 , originMargin.Bottom); marginBottomLeft = new Thickness( 0 , originMargin.Top, originMargin.Right, 0 ); marginBottomRight = new Thickness(originMargin.Left, originMargin.Top, 0 , 0 ); marginLeft = new Thickness( 0 , 0 , originMargin.Right, 0 ); marginRight = new Thickness(originMargin.Left, 0 , 0 , 0 ); } // 尺寸发生改变时: private void EffectNoneWindow_SizeChanged(object sender, SizeChangedEventArgs e) { // 1. 判断是否最大化: if (Math.Abs( this .ActualWidth- maxWidth)< 4 ) // 此处用绝对值判断,是因为窗体的大小,不会刚刚好是最大值。下同。 { bd.Margin = margin5; return ; } // 2. 判断是否分屏: if (Math.Abs( this .Height-maxHeight)< 20 ) { // 在窗体的左侧: bd.Margin = Left == 0 ? marginLeft : marginRight; // Height = maxHeight; return ; } // 3. 判断是否四分屏: if (Math.Abs( this .Width - maxWidth/ 2 )< 20 && Math.Abs( this .Height - maxHeight/ 2 )< 20 ) { if (Left == 0 ) { if (Top == 0 ) { // 左上角 bd.Margin = marginTopLeft; } else { bd.Margin = marginBottomLeft; } } else { if (Top == 0 ) { bd.Margin = marginTopRight; } else { bd.Margin = marginBottomRight; } } return ; } this .bd.Margin = originMargin; } private void OnStateChanged( object ? sender, EventArgs e) { if ( this .WindowState == WindowState.Normal) { // Normal状态时,将bd的Margin设置为初始值 this .bd.Margin = this .originMargin; } else { // 最大化时,将bd的Margin设置为0; this .bd.Margin = margin5; } } // 窗体移动 private void TitleMove( object sender, MouseButtonEventArgs e) { if (e.ChangedButton != MouseButton.Left) return ; // 非左键点击,退出 if (e.ClickCount == 1 ) { this .DragMove(); // 拖动窗体 } else { WindowMax(); // 双击时,最大化或者还原窗体 } } // 最小化 private void Btn_Min( object sender, RoutedEventArgs e) { this .WindowState = WindowState.Minimized; } // 关闭窗体 private void Btn_Close( object sender, RoutedEventArgs e) { this .Close(); } // 最大化、还原 private void Btn_Max( object sender, RoutedEventArgs e) { WindowMax(); } private void WindowMax() { if ( this .WindowState == WindowState.Normal) { this .WindowState = WindowState.Maximized; } else { this .WindowState = WindowState.Normal; } } }
此处,最主要的是EffectNoneWindow_SizeChanged()方法。当窗体的尺寸发生改变时,它会判断窗体在哪个位置,是最大化、两分屏,还是四分屏,并对Margin进行相应的赋值.
至此,一个功能齐全的自定义窗体就搞定了。要改换效果,则只需要将Xaml代码中的Effect替换即可.
有些时候,我们不希望窗体能调整大小,比如初始窗口,仅仅只是在加载的时候显示,程序加载完之后就关闭了.
如果不希望窗体能调整大小,只需设置Windows的ResizeMode = “NoResize”即可.
最后此篇关于WPF学习-自定义窗体(二)的文章就讲到这里了,如果你想了解更多关于WPF学习-自定义窗体(二)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
对于一个科学实验,我写了一个turtle.py ,它会打开一个 800x480 的窗口并绘制一个缓慢增长的黑点。 turtle.py以 C:\Users\kaza>python C:\Users\ka
我开发了一个 swing 应用程序,但每次运行应用程序时都会打开一个新窗口。我希望如果一个窗口已经打开,则其他窗口不允许打开。 最佳答案 Here是一个 Java 单一应用实例的例子: A singl
有没有办法检测主进程中 Electron 的结构? process.platform 似乎也在 x64 机器上返回 win32,我没有在文档中找到任何获取架构的选项。 最佳答案 你试过 process
public short[] HanningWindow(short[] signal_in ,int pos ,int size) { for (int i= pos; i < pos+si
我有一个具有这些属性的 Electron 窗口: mainWindow = new BrowserWindow({ width: 800, height: 600, title: "Aqu
我有一个 Ubuntu 工作站,我正在尝试引导一个 Windows 节点。 Windows 节点在端口 2222 上打开了 ssh。我一直在关注 http://docs.opscode.com/plu
我是一名优秀的程序员,十分优秀!