首页 > 其他分享 >WPF 自定义窗体(一)

WPF 自定义窗体(一)

时间:2023-09-04 18:11:29浏览次数:74  
标签:鼠标 自定义 void private WindowState 窗体 WindowChrome WPF

.Net默认的窗体样式只有四种:None、SingleBorderWindow、ThreeDBorderWindow、ToolWindow,都比较“丑”。而很多时候,我们希望自定义窗体,比如,无边框,有阴影,或者有模糊效果等。

在WPF中,要实现自定义窗体比较简单,主要有两种方法:

1)使用WindowChrome;

2)使用WindowStyle = “None”。

一、使用WindowChrome。

  WindowChrome,可以翻译为:窗体装饰条,官方文档中的定义是:表示一个对象,它描述窗口非工作区区域的自定义。(官方链接:WindowChrome 类 (System.Windows.Shell) | Microsoft Learn

  在官方的解释中,窗口由两部分构成:客户区域,非客户区域。

图中,Client Area表示客户区域;其他的部分,统称为非客户区域。

 

那么WindowChrome的作用是,将客户区域扩展至整个窗体(遮住了非客户区),同时提供部分标准窗体的功能。如下所示:

<Window x:Class="ControlTest.WindowNone"
        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="WindowNone" Height="450" Width="800">
    
    <!-- WindowChrome将客户区域扩展至整个窗体,并遮住标题栏、按钮等-->
    <WindowChrome.WindowChrome>
        <WindowChrome />
    </WindowChrome.WindowChrome>
    
    <Grid>
        <TabControl>
            <TabItem Header="项目"/>
            <TabItem Header="代码"/>
        </TabControl>
    </Grid>
</Window>

   备注:这里的边框,是TabControl的边框,不是窗体的边框。

 

 用上WindowChrome后,会惊奇的发现:在原标题栏的位置,可以用鼠标拖动了;在窗体的四周,可以调整窗体的大小了!Amazing!

但同时,又出现了一个新的问题:窗体中的所以内容,都不能交互(鼠标点击,用户输入)了。

这是为什么呢?可以这样理解。WindowChrome就像一个图层,它将窗体整个覆盖住了。因此窗体上的内容,自然就操作不了。那要如何才能点击呢?

这需要给交互控件,添加WindowChrome的附件属性:IsHitTestVisibleInChrome。如下所示。

    <Grid>
        <!-- 使用WindowChrome的附件属性 -->
        <TabControl WindowChrome.IsHitTestVisibleInChrome="True">
            <TabItem Header="项目"/>
            <TabItem Header="代码"/>
        </TabControl>
    </Grid>

  如果你以为这样就万事大吉了,那只能说太天真了,微软的东西,哪有那么简单的呢??哈哈~ 

  如果真的按照这个代码,你会发现,又不能使用鼠标拖动窗体了。这是为什么呢?明明之前都可以,为何为控件添加了一个附加属性后,就不行了呢?

  问题肯定出在WindowChrome上。那么我们再来看看WindowChrome:

图中有颜色的区域,实际上均为透明的,看不见的。此处附上颜色则是为了方便解释。

 

这个图就是WindowChrome的模型。其中Caption区域,表示标题栏,就是它,允许窗体被鼠标拖动。GlassFrameThickness就是Aero窗体的透明边框(Aero主体只在部分操作系统中支持)。ResizeBorderThickness就是调整窗体大小的边框的粗细,它提供了使用鼠标调整窗体大小的功能。而CornerRadius,则将窗体变成了圆角,它只有在GlassFrameThickness = 0 或者未启用Aero主体的窗口中才有效。。

再回到上面的问题,为什么添加了附加属性,就不能用鼠标拖动窗体了呢?

原因在于,TabControl进入了Caption区域。因为设置了附加属性(IsHitTestVisibleInChrome),表示鼠标可以“击穿”WindowChrome,那么自然就无法“点击”到Caption区域,自然就无法拖动窗体了。

那么如果解决这个问题呢?以及如何添加按钮呢?答案是手动添加标题栏。哈哈~ 如下代码所示:

Xaml代码:

<Window x:Class="ControlTest.WindowNone"
        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="WindowNone" Height="450" Width="800">
    
    <!-- WindowChrome将客户区域扩展至整个窗体,并遮住标题栏、按钮等 -->
    <WindowChrome.WindowChrome>
     <!-- 设置了标题栏的高度 = 30,圆角 = 20 --> <WindowChrome CaptionHeight="30" CornerRadius="20" GlassFrameThickness="0"/> </WindowChrome.WindowChrome> <Border BorderThickness="1"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Border Height="30" Background="YellowGreen"> <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> <!-- 使用WindowChrome的附件属性 --> <TabControl Grid.Row="1" WindowChrome.IsHitTestVisibleInChrome="True"> <TabItem Header="项目"/> <TabItem Header="代码"/> </TabControl> </Grid> </Border> </Window> C# 代码: public partial class WindowNone : Window { public WindowNone() { InitializeComponent(); }
// 最小化 private void Btn_Min(object sender, RoutedEventArgs e) { this.WindowState = WindowState.Minimized; }
  // 最大化、还原 private void Btn_Max(object sender, RoutedEventArgs e) { if(this.WindowState == WindowState.Normal) { this.WindowState = WindowState.Maximized; } else { this.WindowState = WindowState.Normal; } }
  // 关闭窗体 private void Btn_Close(object sender, RoutedEventArgs e) { this.Close(); } }

 

手动添加了标题栏之后,在标题栏上,你就可以放上任何你放的东西。。。。

 

二、使用WindowStyle = "None"

将窗体的WindowStyle属性设置为None后,窗体呈现这样:

<Window x:Class="ControlTest.NoneWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="NoneWindow" Height="450" Width="800"
        WindowStyle="None">
    <Grid>
        <TabControl>
            <TabItem Header="项目"/>
            <TabItem Header="代码"/>
        </TabControl>
    </Grid>
</Window>

  

这里,你会发现,窗体可以通过鼠标调整大小,但是不能用鼠标拖动。那解决的办法是什么呢?同样是手动设置一个标题栏: 

Xaml 代码:
<Window x:Class="ControlTest.NoneWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="NoneWindow" Height="450" Width="800"
        WindowStyle="None" BorderThickness="0" BorderBrush="Transparent">
    <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>
</Window>

C# 代码:

    public partial class NoneWindow : Window
    {
        public NoneWindow()
        {
            InitializeComponent();
        }

        // 窗体移动
        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;
            }
        }

        
    }

  

这种方式下,会发现在窗体的“标题栏”上面,还有一点留白无法去除,同样窗体的边框也是无法去除的。

如果解决?且听下回分解。  

标签:鼠标,自定义,void,private,WindowState,窗体,WindowChrome,WPF
From: https://www.cnblogs.com/raynado/p/17677289.html

相关文章

  • 哔哩哔哩 B站 bilibili 视频倍速设置 视频倍速可自定义
    目录一、复制如下代码二、在B站视频播放页面进入控制台(一)以火狐浏览器为例     (二)以谷歌浏览器为例三、将复制的代码粘贴到下方输入框,并回车Enter即可(一)以火狐浏览器为例     (二)以谷歌浏览器为例 四、然后就可以了一、复制如下代码(该代码用于设置倍速为3,最后......
  • 授权规则-自定义异常结果
        ......
  • C# 在Word文档级自定义中选择一个区域 使用VSTO外接程序选择范围
    你可以使用Range对象在MicrosoftOfficeWord文档中定义和选择范围。有多种方法可以选择整个文档,例如使用Select方法和Range对象,或者使用文档级自定义和Document类的Content属性。适用于:本主题中的信息适用于Word的文档级项目和VSTO外接程序项目。有关详细信息,请参阅Office应用程......
  • WPF项目国际化多语言工具ResXManager使用
    首先在VS的扩展找到ResXManager进行下载安装如果安装提示:vsix安装提示无法成功应用某些修改找到安装程序实例1a5a9225,但其处于不可启重新选中工具进行安装之后即可(有可能之前选中安装了,但是功能不完整,重新点击安装完整即可) 安装完ResXManager之后打开新增语言,然后导出,给......
  • 直播源码,自定义progressBar样式
    直播源码,自定义progressBar样式1、layout中xml布局如下: <RelativeLayout  android:layout_height="16dp"  android:layout_width="match_parent">  <ProgressBar    style="?android:attr/progressBarStyleHorizontal"    android......
  • uniapp app端如何使用插件实现获取手机应用自定义上传
    <u-buttonsize="mini"style="background-color:#3ac908;color:#ffffff;font-size:16rpx;width:110rpx;height:50rpx;"@tap="onUpload">上传</u-button>//以下代码写于根目录下第一个view顶部或跟在自定义导航栏后面<l-fileref="lFile&......
  • WPF 应用适配阿拉伯语注意问题
    给所有Window设置FlowDirection="RightToLeft"属性即可,输入框的光标问题切换到阿拉伯输入法会自动适配。参考微软官方文档:https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/advanced/wpf-globalization-and-localization-overview?view=netframeworkdesktop-4.8 ......
  • 微信小程序自定义头部导航栏
    微信小程序自定义头部导航栏虽然小程序自带的顶部导航栏比较好用,但是扩展性比较差。在实际开发中我们经常需要针对导航栏进行一些功能性操作。比如点击返回按钮返回到固定的页面,设置其他背景颜色字体颜色以及增加一些按钮等等。下面我们一起来看看导航栏的定制;先看下demo的效果:......
  • WPF - 阴影效果
    基本属性:属性说明描述Color设置阴影效果背景色Color="Red"ShadowDepth设置阴影的偏移度ShadowDepth="5"Direction设置阴影的角度Direction="-45"BlurRadius设置阴影模糊程度BlurRadius="20"Opacity设置阴影透明度......
  • elemenui datePicker 日期组件之快捷键的自定义,本周,本月,本季度,上周,上月,上季度
    1,先定义一个日期工具类,或者写在其他的方法中都行。定义工具类可重复使用1exportfunctiongetDateRang(val){2constnow=newDate();//当前日期3constnowDayOfWeek=now.getDay();//今天是本周的第几天4constnowDay=now.getDate();//当日5......