透明
方式1
这种方式透明区域是鼠标穿透的。
1 | <Window |
方式2
这种方式的透明区域鼠标不会穿透,但是性能更好。
1 | <Window |
其中主要的属性是
1 | ResizeMode="CanMinimize" |
和
1 | <WindowChrome.WindowChrome> |
窗口阴影
设置WindowChrome(推荐)
不显示窗口的按钮,但是保留窗口的阴影
1 | <Window.Style> |
注意
这里添加了一个触发器,当窗口最大化的时候设置了边框宽度是6,这是因为虽然我们设置
BorderThickness
为0,但是最大化的时候,框架傻傻的还是减去了默认值6,会导致窗口最大化时显示不全,所以这时候设置触发器,就正好解决了这个问题。
WindowChrome 是 WPF 4.5 中的新特性之一,它允许您完全自定义 Windows 窗口的样式,包括标题栏、窗口边框和窗口阴影等。WindowChrome 类包含一组属性,用于定义窗口的样式和行为。
以下是 WindowChrome 类的主要属性:
- CaptionHeight:窗口标题栏的高度。默认值为 30 像素。
- CornerRadius:窗口边框和标题栏的圆角半径。默认值为 0。
- GlassFrameThickness:在使用 Aero 效果时,控制窗口边框的渐变区域大小。默认值为 1 像素。当为
-1
的时候使用窗口默认样式。 - ResizeBorderThickness:控制窗口边框的大小,以便用户可以通过窗口边缘或角来调整窗口大小。默认值为 6 像素。
- UseAeroCaptionButtons:指示是否应使用 Windows Aero 形式的标题栏按钮。默认值为 true。
- WindowChrome.IsHitTestVisibleInChrome:指示是否应将鼠标单击事件路由到窗口内容。默认值为 false。
- WindowChrome.IsHitTestVisibleInNonClientArea:指示是否应将鼠标单击事件路由到窗口的非客户区域。默认值为 false。
要显示窗口的阴影要设置一下的值
AllowsTransparency="False"
不能透明,透明就没阴影了。WindowStyle="SingleBorderWindow"
不能设置为WindowStyle="None"
,就是我们要保留默认的样式,这样才能显示阴影。GlassFrameThickness="-1"
,当该值为-1的时候,不会CornerRadius
设置圆角的值不生效。
总的来说
保留窗口的默认样式,把标题栏高度设置为0。
为了页面公用我们也可以定义样式
1 | <Style x:Key="ZWinStyle" TargetType="Window"> |
使用
1 | <Window |
窗口默认样式
也就是窗口不是WindowStyle="None"
的情况下,但是我们为了自定义窗口上的按钮,都不会使用这种方式。
1 | <Window.Effect> |
窗口透明
示例
这种方式在最大化的时候,因为阴影宽度的问题会导致四周没靠边。
首先添加窗口透明
1 | <Window |
添加全局样式
1 | <Style x:Key="ShadowStyle" TargetType="Border"> |
使用
1 | <Border Style="{StaticResource ShadowStyle}"> |
注意
阴影区域,也就是Margin的值要是4的倍数,否则界面会模糊。
参数介绍
WPF中的DropShadowEffect提供了设置窗口阴影的功能。
下面是它的参数介绍:
- BlurRadius:模糊半径,用来控制阴影的边缘模糊程度。
- Color:阴影的颜色。
- Direction:阴影的方向,用一个度数来表示。
- Opacity:阴影的不透明度,控制阴影的透明度程度。
- ShadowDepth:阴影的深度,表示阴影相对于元素的距离。
- RenderingBias:阴影的呈现方式,用于指定是以速度优先还是质量优先进行呈现。
可以根据需要对以上参数进行调整,以获取更好的阴影效果。
窗口
去除边框
WPF的默认样式是有边框的,为了去除窗体的边框,可以设置Window的以下属性
1 | WindowStyle="None" |
窗口初始化位置
一旦没了边框之后 默认情况下是无法进行拖拽的 因此初始化位置就比较重要了
WPF的窗体初始化位置属性WindowStartupLocation
分为
- Manual(默认值)
- CenterScreen
- CenterOwner 三种,
默认是Manual 因此要想设置到屏幕中央 使用CenterScreen即可
如果要自定义设置位置 使用Manual后再设置Left和Top属性即可
窗口置顶
1 | this.Topmost = true; |
窗体拖拽
无边框情况下默认是无法拖拽的,如果需要拖拽则为Window的MouseLeftButtonDown绑定事件,并调用默认DragMove方法即可。
XAML:
1 | MouseLeftButtonDown="Window_MouseLeftButtonDown" |
C#:
1 | private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) |
注意
一定不要在外层和内层都添加该方法,会导致拖拽时崩溃。
窗口全屏
1 | this.WindowState = System.Windows.WindowState.Normal; |
窗口是否可见
通过Visibility
判断
1 | if (Visibility == Visibility.Hidden) |
如果判断特定状态使用Visibility
比较好。
通过IsVisible
判断
但要注意,窗口的 IsVisible
属性会在以下情况下变为 false
:
窗口被隐藏:当调用窗口的
Hide()
方法,或者将窗口的Visibility
属性设置为Collapsed
时,窗口会被隐藏,IsVisible
属性值会变为false
。窗口被最小化:当将窗口的
WindowState
属性设置为WindowState.Minimized
或者通过系统的最小化按钮将窗口最小化时,窗口会被最小化并隐藏,IsVisible
属性值会变为false
。窗口被关闭:当调用窗口的
Close()
方法关闭窗口时,窗口会被关闭并隐藏,IsVisible
属性值会变为false
。
需要注意的是,这些操作会直接改变窗口的可见性。
但是,窗口的可见性也可能受到其他因素的影响,例如被其他窗口遮挡而无法显示在屏幕上,此时 IsVisible
仍然为 true
。
因此,根据具体的需求,可能需要综合考虑其他因素来判断窗口是否可见。
窗口激活
有时窗口显示的时候,但是被其它窗口遮挡,我们想让他激活到前台。
1 | if (quesResultsWindow is { Visibility: Visibility.Visible }) |
其中
- Focus 会获取焦点,不会激活前台。
- Activate 只会激活前台,不会获取焦点。
窗口激活状态的变化
WPF的Activated
和Deactivated
事件来监听窗口是否被激活或者失去焦点。
首先,在XAML文件中定义一个窗口:
1 | <Window x:Class="WindowActivationExample.MainWindow" |
接着,在MainWindow.xaml.cs文件中添加Activated
和Deactivated
事件的处理程序:
1 | using System.Windows; |
监听状态变化
在 WPF 中,可以通过绑定窗口的 Visibility
属性并实现可视化状态变化事件的处理程序,来监听窗口可视化状态的变化。具体来说,可以使用 FrameworkElement
的 VisibilityChanged
事件,该事件会在元素的 Visibility
属性值更改时被触发。在窗口中,可以将其绑定到窗口对象的 Visibility
属性,并在窗口可视化状态更改时执行相应的处理程序。
以下是一个在 WPF 窗口中使用 VisibilityChanged
事件的示例:
1 | public partial class MainWindow : Window |
在上面的示例中,我们将窗口的可视化状态绑定到了 VisibilityChanged
事件,并在事件处理程序中进行了相应的处理。
需要注意的是,对于较复杂的应用,通常使用 MVVM 模式来进行开发,将窗口的可视化状态绑定到 ViewModel 中的属性,并在属性更改时触发相应的事件,以便在窗口与 ViewModel 之间进行数据绑定。
窗口拖动
方式1
无边框情况下默认是无法拖拽的,如果需要拖拽则为Window的MouseLeftButtonDown绑定事件,并调用默认DragMove方法即可。
XAML:
1 | MouseLeftButtonDown="WindowMouseLeftButtonDown" |
C#:
1 | private void WindowMouseLeftButtonDown(object sender, MouseButtonEventArgs e) |
注意
一定不要在外层和内层都添加该方法,会导致拖拽时崩溃。
这种方式实现的拖动窗口的顶部会被限制在桌面内。
方式2
要在WPF应用程序中实现窗口拖动功能,你可以利用鼠标事件和窗口的属性来实现。
首先,在窗口的XAML文件中,添加一个鼠标左键按下、移动和释放事件处理程序,并为窗口添加MouseDown
、MouseMove
和MouseUp
事件的处理程序:
1 | <Window x:Class="YourNamespace.MainWindow" |
接下来,在窗口的代码文件中,实现这些事件处理程序:
1 | using System.Windows; |
在这个示例中,当用户按下鼠标左键时,记录下鼠标相对于窗口左上角的起始位置,并标记窗口正在被拖动。在鼠标移动时,计算鼠标移动距离,并根据距离更新窗口的位置。最后,在鼠标释放时,标记窗口停止拖动。
窗口不透明时去掉顶部白边
1 | <Window |
主要是ResizeMode
属性
不在状态栏显示
1 | ShowInTaskbar="False" |
居中显示
1 | WindowStartupLocation="CenterScreen" |
窗口界面模糊
先说结论
像素最好是4的倍数
原因
假如我们电脑的分辨率为1920*1080
,缩放为125%
,那么WPF最大窗口尺寸为1536*864
。也就是都要除以1.25
。
那么我们窗口的宽、高、Margin和Padding都要乘以1.25
才是实际的像素。
只有实际像素为整数时才能显示清晰。
假如我们设置的Margin是10的话,实际像素就是12.5,就会导致页面模糊。
为什么是4的倍数?
我们常见的缩放为100%、125%、150%、175%、200%,这些乘以4都是整数。
最小化/最大化
最小化
1 | private void MiniBtn_Click(object sender, RoutedEventArgs e) |
最大化
1 | private void MaxBtn_Click(object sender, RoutedEventArgs e) |
XML中
1 | WindowState="Maximized" |
居中显示
1 | WindowStartupLocation="CenterOwner" |
获取屏幕的宽高
主显示器的宽高
这个值是实际的像素除以缩放后的值
1 | readonly double _screenWidth = SystemParameters.PrimaryScreenWidth; |
宽高(实际的像素)
1 | int screenWidth = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width; |
获取系统缩放
1 | int screenWidth = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width; |
获取窗口像素位置
1 | private double _left; |
Enter登录
在登录界面我们想使用Enter触发登录的事件
可以在登录按钮上添加
1 | IsDefault="True" |
并且保证别的按钮没有添加这个属性,这样就实现了点击Enter登录的操作。
生命周期
从前到后以此为:
Constructor
Initialized
SourceInitialized 显示窗口,事件发生后获取窗体的句柄,并且可注册全局快捷键。
Activated 活动窗口
Loaded 所有内容都显示给用户之前执行,窗口渲染完成,但是还没有执行任何交互时触发,在程序加载期间做一些初始化操作
Deactivated 多个窗口中切换时,Activated和Deactivated在窗口的生命周期里会发生多次
ContentRendered 窗口第一次完全呈现出来时触发,说明窗口已打开
SourceUpdated用户和窗口进行交互
Closing
Closed
Unloaded
按钮事件
在 WPF 中,为按钮添加事件和解除事件最好在 Loaded 和 Unloaded 生命周期中进行。
Loaded 表示窗口已加载完成,此时所有元素和资源均已初始化完毕,可以安全地添加事件处理程序。
Unloaded 表示窗口即将从内存中卸载,此时应解除所有事件处理程序,以避免资源泄漏。
新线程长期任务
如果我们要在页面启动的时候,同时执行另一个长期执行的线程,这时候如果页面关闭,线程不会关闭,就会造成内存泄漏。
建议添加一个变量在页面关闭事件中设置变量为false,线程也就停止了。
1 | private bool _isStart; |
如果我们还要操作UI线程的元素的时候,一定也要判断一下变量的值,防止页面已销毁而导致崩溃。
1 | if (_isStart) |
Owner
在 WPF 中,设置窗口的 Owner(拥有者)有以下作用:
创建模态对话框
创建模态对话框:
使用 Owner 属性可以将一个窗口设置为另一个窗口的所有者。
这意味着拥有者窗口会成为被拥有窗口的模态对话框的所有者。
被拥有窗口将保持在拥有者窗口之上,用户无法与其他窗口进行交互,直到关闭拥有者窗口或者调用被拥有窗口的 Close 方法。
这对于实现需要顺序进行的工作流程或者确保用户完成某个任务非常有用。
示例代码:
1 | MainWindow ownerWindow = new MainWindow(); |
实现窗口层次结构
实现窗口层次结构:
设置窗口的 Owner 属性可以创建一个窗口层次结构,其中子窗口与父窗口相关联。
当父窗口最小化、最大化或者关闭时,相关联的子窗口也会进行相应的处理,以确保用户体验的连续性。
示例代码:
1 | MainWindow parentWindow = new MainWindow(); |
在此示例中,当 parentWindow 最小化、最大化或者关闭时,childWindow1 和 childWindow2 也会相应地进行处理。
实现窗口间的数据传递
实现窗口间的数据传递:
通过 Owner 属性,你可以在窗口之间传递数据。
拥有者窗口可以提供对必要数据的访问,以便子窗口使用或更新这些数据。
示例代码:
在拥有者窗口中:
1 | ChildWindow childWindow = new ChildWindow(); |
在子窗口中:
1 | MainWindow ownerWindow = (MainWindow)this.Owner; |
通过 Owner 属性,子窗口可以访问拥有者窗口中的数据并进行操作。
总结:
设置窗口的 Owner 属性可以创建模态对话框、实现窗口层次结构和实现窗口间的数据传递。
同时,使用 Owner 属性可以提升用户体验和界面交互的一致性。