WPF--->自定义窗口

Window类继承自ContentControl类。
可以通过设置WindowStyle=“None”,完全移除窗口框架,从而创建一个可完全定制的窗口,但是有各种各样的不方便,所以本文使用WindowChrome.WindowChrome来自定义窗口

基础知识

Window类基本属性

属性作用
AllowsTransparency窗口是否透明True 允许其他窗口透过该窗口显示
False 窗口背后的内容永远不能显示,并且透明的背景被呈现为黑色背景
当与WindowStyle="None"属性结合使用,可创建形状不规则的窗口
Icon窗口图标
Top&Left设置屏幕窗口左上角到
屏幕顶部与左侧的距离
当WindowStartupPosition属性设置为Manual,可在窗口显示之前设计窗口位置
ResizeMode用户是否可以改变窗口尺寸NoResize 完全锁定窗口尺寸
CanMinimize 只允许最小化窗口
CanResize允许任意改变窗口尺寸
CanResizeWithGrip 在窗口右下角添加图形细节,表示可以改变窗口尺寸
ReStroeBounds获取窗口边界
ShowInTaskbar在任务栏Alt+Tab中显示True
False
SizeToContent创建自动放大缩小尺寸的窗口Manual 禁止窗口自动改变尺寸
Height、Whidth、Width And Height 允许窗口在不同方向进行扩展以适应动态内容。
当使用SIzeContent属性时窗口尺寸可以放大到超出屏幕边界
Title窗口标题栏
Topmost在最上层显示True 在应用程序的所有所有其他窗口的上面显示(除非其他窗口的Topmost也为True)
WindowStartupLocation窗口初始位置设置Manual 使用Left&Top设置窗口位置
CenterScreen 在屏幕中心显示窗口
CenterOwner 在父窗口中心显示
WindowState控制当前窗口是否最大化,最小化或处于正常状态Normal 正常
Maximized 最大化
WindowStyle决定窗口边框SingleBorderWindow 默认值None 在没有标题栏的区域周围有一条凸起的细边框

显示

方法效果解释
Show()显示非模态窗口
ShowDialog()显示模态窗口阻止用户访问父窗口

自定义窗口

Window的标准布局很简单,大致上就是标题栏和内容。以下代码仅供参考,部分依赖文件未贴出
相关链接:【tilte拖动与双击相应的实现】、【HandyControl控件库

  • xaml文件
       <!--按钮样式-->
    <Style x:Key="WindowBaseButton" TargetType="{x:Type Button}">
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="BorderThickness" Value="0"/>
        <Setter Property="Foreground" Value="Black"/>
        <Setter Property="Height" Value="35"/>
        <Setter Property="Width" Value="40"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Border BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" >
                        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Margin="{TemplateBinding Padding}"/>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter Property="Background" Value="#bbc2cc"/>
                        </Trigger >
                        <Trigger Property="IsPressed" Value="True">
                            <Setter Property="Background" Value="#8994a1"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <!--关闭按钮-->
    <Style x:Key="WindowClosedButton" TargetType="{x:Type Button}">
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="BorderThickness" Value="0"/>
        <Setter Property="Height" Value="35"/>
        <Setter Property="Width" Value="40"/>
            <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                        <Border BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" >
                            <!--<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Margin="{TemplateBinding Padding}"/>-->
                        <Path x:Name="ClosedPath" Fill="{DynamicResource PrimaryContentBrush}" Height="15" Width="15" Data="{DynamicResource WindowsCloseGeometry}"/>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter Property="Background" Value="{DynamicResource LightRedBrush}"/>
                            <Setter Property="Fill" Value="{DynamicResource LightTextBrush}" TargetName="ClosedPath"/>
                        </Trigger >
                        <Trigger Property="IsPressed" Value="True">
                            <Setter Property="Background" Value="{DynamicResource DarkRedBrush}"/>
                            <Setter Property="Fill" Value="{DynamicResource LightTextBrush}" TargetName="ClosedPath"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
    <Style x:Key="CommonWindowStyle" TargetType="{x:Type mw:CommonWindow}">
        <Setter Property="HeaderHeight" Value="35"/>
        <Setter Property="Background" Value="{DynamicResource LightTextBrush}"/>
        <Setter Property="Title" Value="CommonWindow"/>
            <Setter Property="WindowChrome.WindowChrome">
            <Setter.Value>
                <WindowChrome CornerRadius="0" GlassFrameThickness="1" UseAeroCaptionButtons="False" NonClientFrameEdges="None"/>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type mw:CommonWindow}">
                    <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" x:Name="WindowBorder">
                        <Grid x:Name="root" Background="{TemplateBinding Background}"  Margin="{TemplateBinding Padding}">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="*"/>
                            </Grid.RowDefinitions>
                            <Grid x:Name="PART_WindowTitleGrid" Grid.Row="0">
                                <Border Name="header" Background="{DynamicResource WindowTitleBrush}" 
                                        BorderThickness="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness}"
                                        Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=HeaderHeight}">
                                    <DockPanel Height="Auto">
                                        <!--图标-->
                                        <StackPanel VerticalAlignment="Center" Orientation="Horizontal" DockPanel.Dock="Left">
                                            <Image Source="{TemplateBinding Icon}" MaxHeight="20" MaxWidth="20" Margin="10,0,0,0"/>
                                            <TextBlock Text="{TemplateBinding Title}" FontSize="14" FontFamily="Microsoft Yihi" 
                                                       VerticalAlignment="Center" Margin="6,0,0,0"></TextBlock>
                                        </StackPanel>
                                        <StackPanel DockPanel.Dock="Right"  HorizontalAlignment="Right" 
                                                    VerticalAlignment="Top" Orientation="Horizontal" Height="Auto"
                                                    WindowChrome.IsHitTestVisibleInChrome="True">
                                            <Button x:Name="btnMin"  Style="{StaticResource WindowBaseButton}" 
                                                    Height="{Binding RelativeSource={RelativeSource TemplatedParent},
                                                        Path=HeaderHeight}">
                                                <Button.Content>
                                                    <Path x:Name="MiniPath" Fill="{DynamicResource PrimaryContentBrush}" Data="{DynamicResource WindowsMinGeometry}"  Width="15" Height="15"/>
                                                </Button.Content>
                                            </Button>
                                            <Button x:Name="btnMax" Style="{StaticResource WindowBaseButton}" Height="{Binding 
                                                    RelativeSource={RelativeSource TemplatedParent},Path=HeaderHeight}">
                                                <Button.Content>
                                                    <mw:SimplePanel>
                                                        <Path x:Name="MaxPath" Stroke="{DynamicResource PrimaryContentBrush}" Height="15" Width="15" Stretch="Uniform" Data="{DynamicResource WindowsMaxGeometry}"/>
                                                    </mw:SimplePanel>
                                                </Button.Content>
                                            </Button>
                                            <Button x:Name="btnClose" 
                                                    Style="{StaticResource WindowClosedButton}" 
                                                    Height="{Binding RelativeSource={RelativeSource TemplatedParent},
                                                        Path=HeaderHeight}">
                                            </Button>
                                        </StackPanel>
                                    </DockPanel>
                                </Border>
                            </Grid>
                            <Border Grid.Row="1" 
                                BorderBrush="{TemplateBinding BorderBrush}"
                                Background="{TemplateBinding Background}"
                                DockPanel.Dock="Top" Height="Auto">
                                <AdornerDecorator>
                                    <ContentPresenter />
                                </AdornerDecorator>
                            </Border>
                        </Grid>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="WindowState" Value="Maximized">
                            <Setter Property="Data" Value="{DynamicResource WindowsRestoreGeometry}" TargetName="MaxPath"/>
                        </Trigger>
                        <Trigger Property="WindowState" Value="Normal">
                            <Setter Property="Data" Value="{DynamicResource WindowsMaxGeometry}" TargetName="MaxPath"/>
                        </Trigger>
                            <Trigger Property="WindowState" Value="Minimized">
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
  • 2.Cs文件
    using MaxwellControl.Tools;
    using MaxwellControl.Tools.Interop;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Input;
    using System.Windows.Shell;
    
    namespace MaxwellControl.Controls
    {
        public class CommonWindow : Window
        {
            private Grid root;
            private Button minBtn;
            private Button maxBtn;
            private Button closeBtn;
            private Border header;
            private bool taskBarHide;
            private readonly Thickness _commonPadding;
            Thickness const_maxpadding = new Thickness(8, 8, 8, 8);
            Thickness const_normalpadding = new Thickness(0, 0, 0, 0);
    
            public CommonWindow()
            {
                Padding = const_normalpadding;
                _commonPadding = Padding;
                taskBarHide = false;
                //绑定Window的关于title的相应处理
                var chrome = WindowChrome.GetWindowChrome(this);
                BindingOperations.SetBinding(chrome, WindowChrome.CaptionHeightProperty,
                    new Binding(nameof(HeaderHeight)) { Source = this });
            }
    
            static CommonWindow()
            {
                StyleProperty.OverrideMetadata(typeof(CommonWindow), new FrameworkPropertyMetadata(ResourceHelper.GetResource<Style>("CommonWindowStyle")));
            }
    
            public override void OnApplyTemplate()
            {
                base.OnApplyTemplate();
    			//获取控件上的子部分
                minBtn = base.GetTemplateChild("btnMin") as Button;
                maxBtn = base.GetTemplateChild("btnMax") as Button;
                closeBtn = base.GetTemplateChild("btnClose") as Button;
                root = (Grid)Template.FindName("root", this);
                header = base.GetTemplateChild("header") as Border;
    
                minBtn.Click += (o, e) => WindowState = WindowState.Minimized;
                maxBtn.Click += MaxBtn_Click;
                closeBtn.Click += (o, e) => Close();
            }
    
    
    
            private void MaxBtn_Click(object sender, RoutedEventArgs e)
            {
                if (WindowState == WindowState.Normal)
                {
                    WindowState = WindowState.Maximized;
                }
                else
                {
                    WindowState = WindowState.Normal;
                }
            }
    
    
            #region properties
    
            //是否全屏
            public bool IsFullScreen
            {
                get { return (bool)GetValue(IsFullScreenProperty); }
                set { SetValue(IsFullScreenProperty, value); }
            }
    
            // Using a DependencyProperty as the backing store for FullScreen.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty IsFullScreenProperty =
                DependencyProperty.Register("FullScreen", typeof(bool), typeof(CommonWindow), new PropertyMetadata(false));
    
    		//title的高度
            public int HeaderHeight
            {
                get { return (int)GetValue(HeaderHeightProperty); }
                set { SetValue(HeaderHeightProperty, value); }
            }
    
            // Using a DependencyProperty as the backing store for HeaderHeight.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty HeaderHeightProperty =
                DependencyProperty.Register("HeaderHeight", typeof(int), typeof(CommonWindow), new PropertyMetadata(0));
    
    
    
            #endregion
    		
    		//状态改变执行的操作
            protected override void OnStateChanged(EventArgs e)
            {
                base.OnStateChanged(e);
                if (WindowState == WindowState.Maximized)
                {
                    if (taskBarHide == false)
                    { 
                        Padding = const_maxpadding;
                    }
                    if (IsFullScreen)
                    {
                        HeaderHeight = 0;
                        header.Visibility = Visibility.Hidden;
                    }
                    else
                    {
                        HeaderHeight = 35;
                        header.Visibility = Visibility.Visible;
                    }
                }
                else if (WindowState == WindowState.Normal)
                {
                    Padding = const_normalpadding;
                }
            }
            
    		//根据不同情况为Padding赋值
            protected override void OnSourceInitialized(EventArgs e)
            {
                this.GetHwndSource()?.AddHook(HwndSourceHook);
                base.OnSourceInitialized(e);
            }
            private IntPtr HwndSourceHook(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
            {
                switch (msg)
                {
                    case InteropValues.WM_WINDOWPOSCHANGED:
                        Padding = WindowState == WindowState.Maximized ? WindowHelper.WindowMaximizedPadding : _commonPadding;
                        break;
                    case InteropValues.WM_GETMINMAXINFO:
                        WmGetMinMaxInfo(hwnd, lparam);
                        Padding = WindowState == WindowState.Maximized ? WindowHelper.WindowMaximizedPadding : _commonPadding;
                        break;
                }
    
                return IntPtr.Zero;
            }
            //判断任务栏是否隐藏,根据不同情况进行处理
            private void WmGetMinMaxInfo(IntPtr hwnd, IntPtr lParam)
            {
                var mmi = (InteropValues.MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(InteropValues.MINMAXINFO));
                var monitor = InteropMethods.MonitorFromWindow(hwnd, InteropValues.MONITOR_DEFAULTTONEAREST);
    
                if (monitor != IntPtr.Zero && mmi != null)
                {
                    InteropValues.APPBARDATA appBarData = default;
                    var autoHide = InteropMethods.SHAppBarMessage(4, ref appBarData) != 0;
                    taskBarHide = autoHide;
                    if (autoHide)
                    {
                        var monitorInfo = default(InteropValues.MONITORINFO);
                        monitorInfo.cbSize = (uint)Marshal.SizeOf(typeof(InteropValues.MONITORINFO));
                        InteropMethods.GetMonitorInfo(monitor, ref monitorInfo);
                        var rcWorkArea = monitorInfo.rcWork;
                        var rcMonitorArea = monitorInfo.rcMonitor;
                        mmi.ptMaxPosition.X = Math.Abs(rcWorkArea.Left - rcMonitorArea.Left);
                        mmi.ptMaxPosition.Y = Math.Abs(rcWorkArea.Top - rcMonitorArea.Top);
                        mmi.ptMaxSize.X = Math.Abs(rcWorkArea.Right - rcWorkArea.Left);
                        mmi.ptMaxSize.Y = Math.Abs(rcWorkArea.Bottom - rcWorkArea.Top - 1);
                    }
                }
    
                Marshal.StructureToPtr(mmi, lParam, true);
            }
        }
    }
    
    
    

参考

WPF编程宝典
博客园的一篇
比较简单基础的一篇


遇到的一些难缠问题

  1. 进行如下方式使用自定义控件,创建不了窗口资源,在OnApplyTemplate中使用GetTemplateChild无法获取子控件,返回null,但是在cs中使用CommonWindow window=new CommonWindow();可以创建窗口并正常显示。
     <my:CommonWindow x:Class="Maxwell_VS2017Demo.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
       <Grid>
        </Grid>
    </my:CommonWindow>
    
    最后发现是按钮中的path资源没有获取到,本来用的是StaticResource获取资源改为DynamicResource后正常,所以要注意StaticReSource与DynamicResource的区别
实现这个功能,你需要按照以下步骤进行操作: 1. 创建一个 WPF 应用程序。 2. 在主窗口中设计一个按钮。 3. 创建一个新的 WPF 窗口用来显示自定义窗口内容。 4. 在按钮的点击事件中,实例化自定义窗口并显示出来。 下面是详细的步骤: 1. 创建一个 WPF 应用程序。 打开 Visual Studio,选择“文件”>“新建”>“项目”,在“新建项目”对话框中选择“WPF 应用程序”。 2. 在主窗口中设计一个按钮。 打开 MainWindow.xaml 文件,在窗口上添加一个按钮: ``` <Button Content="打开自定义窗口" Click="Button_Click"/> ``` 3. 创建一个新的 WPF 窗口用来显示自定义窗口内容。 在“解决方案资源管理器”中右键单击项目,选择“添加”>“新建项”,在“添加新项”对话框中选择“WPF 窗口”,命名为“CustomWindow.xaml”。 在 CustomWindow.xaml 中添加一些内容,如一个文本框: ``` <Grid> <TextBox Text="这是自定义窗口"/> </Grid> ``` 4. 在按钮的点击事件中,实例化自定义窗口并显示出来。 在 MainWindow.xaml.cs 文件中,添加以下代码: ``` private void Button_Click(object sender, RoutedEventArgs e) { CustomWindow customWindow = new CustomWindow(); customWindow.ShowDialog(); } ``` 这个代码在按钮的点击事件中实例化 CustomWindow 窗口,并通过 ShowDialog() 方法显示出来。 现在,你可以运行应用程序并点击按钮,就会弹出自定义窗口了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值