WPF绘制自定义窗口

72 篇文章 9 订阅

简介: 原文:WPF绘制自定义窗口 WPF是制作界面的一大利器,下面就用WPF模拟一下360的软件管理界面,360软件管理界面如下: 界面不难,主要有如下几个要素: 窗体的圆角 自定义标题栏及按钮 自定义状态栏 窗体的半透明效果 窗体4周有一圈半透明阴影(抓的图上看不出来) 实现思路很简单,首先隐藏默认窗口的标题栏和边框,然后用WPF的Border或Canvas等元素模拟定义窗体的标题栏、内容区和状态栏。

在这里插入图片描述
界面不难,主要有如下几个要素:

窗体的圆角
自定义标题栏及按钮
自定义状态栏
窗体的半透明效果
窗体4周有一圈半透明阴影(抓的图上看不出来)
实现思路很简单,首先隐藏默认窗口的标题栏和边框,然后用WPF的Border或Canvas等元素模拟定义窗体的标题栏、内容区和状态栏。

具体实现如下:

第一步:定义义个窗口基类,继承自Window,在构造函数中加载自定义窗口的样式文件,代码如下:

public partial class WindowBase:Window

{

InitializeTheme();

}

private void InitializeTheme()

{

string themeName = ConfigManage.CurrentTheme;//样式所在的文件夹

App.Current.Resources.MergedDictionaries.Add(Application.LoadComponent(new Uri(string.Format("../Theme/{0}/WindowBaseStyle.xaml", themeName), UriKind.Relative)) as ResourceDictionary);

}

接下来,就可以在WindowBaseStyle.xaml样式文件中定义窗口元素及样式了。

第二步:重写窗口模板

因为Window和Button等控件一样,实际是继承自System.Windows.Controls.Control类,所以可以通过使用 ControlTemplate 自定义控件的外观 ,代码如下:

<!--基窗口样式-->

<Style x:Key="BaseWindowStyle" TargetType="{x:Type Window}">

<Setter Property="Template" Value="{StaticResource BaseWindowControlTemplate}"/>

<Setter Property="Background" Value="Transparent" />
<Setter Property="WindowStyle" Value="None" />
<Setter Property="AllowsTransparency" Value="True" />
</Style>

<!--基窗口模板-->
<ControlTemplate x:Key="BaseWindowControlTemplate" TargetType="{x:Type Window}">
<Grid Width="{Binding ElementName=w, Path=Width}" Height="{Binding ElementName=w, Path=Height}">
<!—第四步介绍如下Border元素的作用—>
<Border BorderThickness="5" CornerRadius="6" BorderBrush="#000000" Opacity=".08"></Border>
<!—第三步介绍borderBg元素的作用—>
<Border x:Name="borderBg" Margin="5" Background="#000000" BorderBrush="#ffffff" Opacity=".8" BorderThickness="2" CornerRadius="{StaticResource winCorner}" Style="{StaticResource winStyle}">
<!—定义窗口的元素,Grid的四行分别为标题栏、内容、状态栏上的横线、状态栏-->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="1"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
</Grid.RowDefinitions>
<Border Grid.Row="0" Background="#4f535d" CornerRadius="{StaticResource winTitleCorner}" Style="{StaticResource titleStyle}"></Border>
<Canvas Grid.Row="2" Background="#42464d"></Canvas>
<Border Grid.Row="3" CornerRadius="{StaticResource winStatusCorner}"></Border>
</Grid>
</Border>
<Grid Margin="7">
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="1"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
</Grid.RowDefinitions>
<!--标题栏框-->
<Border x:Name="borderTitle" Grid.Row="0" CornerRadius="{StaticResource winTitleCorner}" Style="{StaticResource titleStyle}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<Grid Background="Transparent">
<TextBlock Text="{Binding ElementName=w, Path=Title}" Foreground="White" Opacity=".75" HorizontalAlignment="Left"></TextBlock>
<StackPanel HorizontalAlignment="Right" VerticalAlignment="Top" Visibility="Hidden" Orientation="Horizontal">
<!--关闭按钮-->
<Button x:Name="btnMin" Style="{StaticResource minBtnStyle}"></Button>
<Button x:Name="btnClose" Style="{StaticResource closeBtnStyle}"></Button>
</StackPanel>
</Grid>

</Border>

<!--内容-->

<Grid x:Name="gridContent" Grid.Row="1">

<ContentPresenter />

</Grid>

 

<Border Grid.Row="3" CornerRadius="{StaticResource winStatusCorner}">

<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" >

<Button x:Name="btnYes" Style="{StaticResource btnStyle}"></Button>

<Button x:Name="btnNo" Style="{StaticResource btnStyle}"></Button>

</StackPanel>

</Border>

</Grid>

</Grid>

</ControlTemplate>

需要注意的是,实际代码中应该将BaseWindowControlTemplate的定义放到BaseWindowStyle的前边,否则会抛出异常。

第三步:实现半透明

用Js实现过遮罩型的模态窗口的同学都知道,如果将元素如按钮直接放到一个半透明的Div中,会发现按钮本身也半透明了,这显然不是我们所希望的,我们只需要背景半透明,元素本身透明度不受影响,实现的思路应该是这样,将按钮和div平级,利用定位属性将按钮和半透明的div保持相对位置,而不是将按钮放入Div中。

WPF中,实现方式和其一样,请看第二步中的x:Name="borderBg"的Border元素的定义。它和后面的Grid元素定义的实际窗口是同级的。

第四步:实现窗体四周半透明的环绕

这个先简单用一个半透明具有一定宽度的Border来模拟,代码如步骤二中所示,后续考虑做成类似外发光的效果。

第五步:实现最小化、关闭、拖动等事件

在WindowBase的构造函数中,添加如下代码:

this.Loaded += delegate
{
            InitializeEvent();
};
private void InitializeEvent()
{
 ControlTemplate baseWindowTemplate = (ControlTemplate)App.Current.Resources["BaseWindowControlTemplate"];

            Border borderTitle = (Border)baseWindowTemplate.FindName("borderTitle", this);
            Button closeBtn = (Button)baseWindowTemplate.FindName("btnClose", this);
            Button minBtn = (Button)baseWindowTemplate.FindName("btnMin", this);
            YesButton = (Button)baseWindowTemplate.FindName("btnYes", this);
            NoButton = (Button)baseWindowTemplate.FindName("btnNo", this);

            minBtn.Click += delegate
            {
                MinWin();
            };

            closeBtn.Click += delegate
            {
                this.Close();
            };

            borderTitle.MouseMove += delegate(object sender, MouseEventArgs e)
            {
                if (e.LeftButton == MouseButtonState.Pressed)
                {
                    this.DragMove();
                }
            };
}

注意, InitializeEvent方法必须放到Loaded事件处理函数中,否者会找不到按钮。

第六步: 定义最小化,关闭按钮的样式

实际上也是定义Template属性,定义方法类似于窗口模板的定义,详细见附件中完整代码。

到此,自定义窗口的基类就打造完成,完整代码见附件。

使用方法很简单,新建一个WPF窗口后将窗体的基类改成上面定义的WindowBase,同时注意将Xmal文件的根元素改成如下形式:
  <my:WindowBase xmlns:my=“clr-namespace:Ezhu.WPFWin”…
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值