WPF界面设计技巧(9)—使用UI自动化布局

时间:2022-09-09 11:29:13

原文:WPF界面设计技巧(9)—使用UI自动化布局

    WPF界面设计技巧(9)—使用UI自动化布局

    最近一直没时间更新这系列文章,因为我一直在埋头编写我的第一个WPF应用程序:MailMail

    今天开始编写附属的加密/解密工具,对UI自动化布局有些心得,就此分享出来。

    我们先来看一下实现的效果:

    WPF界面设计技巧(9)—使用UI自动化布局

    这样的界面是怎么个自动法呢?请看下图:

    WPF界面设计技巧(9)—使用UI自动化布局

    就是说界面在适度的伸缩时,不会破坏其布局结构及美观性。

    这样做有什么好处呢?你可以想象以下情况:

    1.需要用户或通过程序控制变更窗体尺寸以适应特殊要求时。UI自动化可以伸缩各元素以适应变化后的窗体。

    2. 软件语言变更,或需要字体/局部元素缩放时。将设计初始时的语言改变为其他语言,按钮、标签等元素呈现所需的最小空间都会有增减,UI自动化可以调整变动元素,并使与之相关的元素也能做出相应的调整。

    3.需要对UI设计进行更改时。可以说执行UI自动化是一件一劳永逸的事,此后你都不必再为诸如一个标签的文字变更而去调整其他元素的坐标与尺寸了。

    当然,相比通过窗体设计器“画”界面来说,UI自动化需要更多的知识与经验、更复杂的设计步骤以及更少的可视化编辑器支持,有时可视化的编辑行为甚至会破坏你已有的UI自动化布局,所以要谨慎操作。

    下面我们就来谈一谈UI自动化所需的各种技巧:

    让窗口适应内容的大小

    我们通常所做的都是为Window设置固定的尺寸,然后再向里面填东西,但是也许反过来会更便于操作和使用。

    清除Window的宽度和高度,并为之设置 SizeToContent="WidthAndHeight" 即可。

    同理,Window内的布局容器(如Grid)也应当避免使用绝对宽度和高度,除非在其内容无法决定宽度或高度的情况下。

    但请注意,此类设置可以留在布局即将完成时再进行,否则你可能会在编辑器里看到一个0宽0高的窗体,从而没有了可视化的操作空间。或者,你可以为容器设置较小的MinHeight和MinWidth值,这样它们即保留了伸缩特性,又会具有一定的可视/操作空间。

    使用Grid进行全局性布局

    微软把 Grid 作为 Visual Studio 的默认 WPF 模板的布局不是没有道理的,Grid的确可为各种布局控件之首。

    新接触WPF的朋友可能都对这个复杂的家伙有所退避,比如我开始就每次都把它删掉,换成简单的WrapPanel什么的,可一旦掌握了使用它的方法,那真是爱不释手。

    Grid 可以说是结合了传统的表格布局与坐标布局的优点的新型布局方案。

    WPF界面设计技巧(9)—使用UI自动化布局

    如你所见,蓝色的线条就是Grid划分的格子,一些元素老老实实的呆在一个格子里,还有一些毫不客气的横跨了多个格子。

    要设计这样的布局,你需要拿出当年W3C跑出来叫板之前的表格布局网页理念,才能游刃有余地安排元素。

    元素在格子内的相对位置由其 Margin 操控。

    其相对的方向采用上、下、左、右均可,但横向和竖向都至少依赖一个方向,通过VerticalAlignment和HorizontalAlignment属性设置。

    我们来看一下我这个布局的Grid是如何定义的:

    WPF界面设计技巧(9)—使用UI自动化布局

    我定义了3个列,都没有设置宽度,这三列用来承载最下方的三个按钮,我希望按钮的最小尺寸会根据其内容而定,所以不进行绝对值设置。

    我又定义了5个行,其中4个是具有绝对的高度值,中间的一个就是ListBox所在的区域,我希望界面高度伸缩时,唯一可随之变化的就是这个区域,所以设置为*,但是这时如果我不为Grid指定绝对高度值的话,Grid将无法判断中间这个区域的高度具体应为多少,它把它会变为0,所以我指定了Grid的高度为391。

    让按钮自动化

    我们可以不为按钮指定固定的宽度或高度,这样它就会随其内容而伸缩了,不过这样按钮边缘会紧贴其内容,这可以通过设置其Padding属性来进行调整:

    WPF界面设计技巧(9)—使用UI自动化布局

    用内容和 Padding 属性撑起了按钮的最小尺寸后,还可以通过 Margin 属性与其所在的 Grid 格子边缘进行关联,这样在格子变小时,不会小于按钮的最小尺寸,格子变大时,按钮会随之伸展。

    其他元素大都也与按钮同理,如Label、TextBlock。

    利用DockPanel进行局部布局

    虽然Grid很棒,但我们不能完全依赖于它,满屏幕画上密密麻麻的格子或是一层又一层嵌套的Grid都不便于设计和维护,并且Grid布局会消耗很多的运算资源。

    对于局部的布局,可以采用更轻量级的布局方案,有时会获得更好的收效,DockPanel就是一种简便的表格布局控件。

    我通过DockPanel实现了这个区域的布局:

    WPF界面设计技巧(9)—使用UI自动化布局

    这个区域的布局要求是:

    1.标签居左,采用最小宽度

    2.按钮居右,采用最小宽度

    3.中间的空档由密码框完全占据

    实现的代码是这样:

    WPF界面设计技巧(9)—使用UI自动化布局

    通过DockPanel.Dock属性可以设置元素位于DockPanel布局方位。

    标签未设置该属性,因为其默认为居左,也就是DockPanel.Dock="Left"。

    按钮设置为 DockPanel.Dock="Right" 。

    本该排列在第二,也就是会居中并填满空白区域的密码框写在了最后,并且也未设置DockPanel.Dock属性,难道它也是采用了默认的 DockPanel.Dock="Left" 吗?非也,如果你显式设置为DockPanel.Dock="Left",它就会向左排在标签后面,并缩成一小团,非常难看。这其实是因为DockPanel有一个默认为真的属性:

    WPF界面设计技巧(9)—使用UI自动化布局

    最后一个元素会用以填满剩余的区域。

    这个设计手法看起来是不是很像CSS布局时设置的Float浮动属性?

    好了,就分享到这里了,代码奉上:

Code
<Window x:Class="MailMailPassBox.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Style="{StaticResource subWindow}"
    MouseLeftButtonDown="Window_MouseLeftButtonDown"
    Loaded="Window_Loaded"
        DragEnter="Window_DragEnter"
        Drop="Window_Drop"
    Title="Window1" WindowStartupLocation="CenterScreen" SizeToContent="WidthAndHeight" ShowInTaskbar="True" AllowDrop="True">
    <Grid Height="391">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="15" />
            <RowDefinition Height="60" />
            <RowDefinition Height="*" />
            <RowDefinition Height="28" />
            <RowDefinition Height="42" />
        </Grid.RowDefinitions>
        <Border Background="#989898" BorderBrush="#989898" BorderThickness="2,0,2,2"  Margin="0,0,5.643,0"  Height="14.75" VerticalAlignment="Top" Grid.ColumnSpan="3" HorizontalAlignment="Right" Width="111">
            <WrapPanel>
            <CheckBox ToolTip="{StaticResource 窗口总在最前提示}" Height="12.75" Name="top" Click="top_Click" Background="{StaticResource top}" Width="35" Content="Close" Margin="0,0,1,0" HorizontalAlignment="Stretch" VerticalAlignment="Top" Template="{StaticResource barCheckBox}"/>
            <Button Height="12.75" Name="mini"  ToolTip="{StaticResource 最小化提示}"  Click="mini_Click" Background="{StaticResource mini}" Width="35" Content="Close" Margin="0,0,1,0" HorizontalAlignment="Stretch" VerticalAlignment="Top" Template="{StaticResource barButton}"/>
            <Button Height="12.75" Name="close" ToolTip="{StaticResource 关闭提示}" Click="close_Click" Background="{StaticResource close}" Width="35" Content="Close" Margin="0" HorizontalAlignment="Stretch" VerticalAlignment="Top" Template="{StaticResource barButton}"/>
            </WrapPanel>
        </Border>
        <Rectangle Fill="{StaticResource title2}" Margin="7,0" Name="rectangle1" Stroke="Black" Grid.Row="1" StrokeThickness="0" Grid.ColumnSpan="3" />
        <GroupBox Grid.Row="2" Margin="7" Name="groupBox1" Grid.ColumnSpan="3">
            <GroupBox.Header>
                <WrapPanel>
                    <TextBlock>待加密/解密文件 (</TextBlock>
                    <TextBlock Text="{Binding ElementName=listBox1, Path=Items.Count}"/>
                    <TextBlock>)</TextBlock>
                </WrapPanel>
            </GroupBox.Header>
            <ListBox PreviewMouseRightButtonDown="listBox1_PreviewMouseRightButtonDown" MouseDoubleClick="listBox1_MouseDoubleClick" ToolTip="{StaticResource 文件列表提示}" Name="listBox1" SelectionMode="Multiple">
                <ListBox.ContextMenu>
                    <ContextMenu>
                        <MenuItem Name="cmi2" Header="删除所有选中的文件" Click="cmi2_Click"/>
                        <MenuItem Name="cmi3" Header="清空文件列表" Click="cmi3_Click"/>
                    </ContextMenu>
                </ListBox.ContextMenu>
            </ListBox>
        </GroupBox>
        <DockPanel Grid.Row="3" Margin="0" Name="dockPanel1" Grid.ColumnSpan="3">
            <Label Height="28" Name="label1" Margin="7,0,0,0">密钥:</Label>
            <Button Height="23" Name="button4" DockPanel.Dock="Right" Padding="8,3" Margin="7,0">粘帖入</Button>
            <PasswordBox Height="23" Name="passwordBox1"/>
        </DockPanel>
        <Button Grid.Row="4" Margin="7" Name="button1" Padding="8,3" MinWidth="64">直接加密/解密</Button>
        <Button Grid.Column="1" Grid.Row="4" Margin="0,7" Name="button2" Padding="8,3" MinWidth="64">加密/解密并备份原文件</Button>
        <Button Grid.Column="2" Grid.Row="4" Margin="7" Name="button3" Padding="8,3" MinWidth="64">加密/解密到指定目录..</Button>
    </Grid>
</Window>

当然,你不能期待直接编译或使用这个代码了,它只是我的程序的一部分。

我会在以后更多地分享我在编写 MailMail 期间获得的经验的,现在的任务是赶紧把它造出来,嘿嘿。

现在是这个样子滴:

WPF界面设计技巧(9)—使用UI自动化布局

更多抓图还是看我这个帖子了:一起来乐邮邮——妙趣小软件:MailMail发布预告

WPF界面设计技巧(9)—使用UI自动化布局的更多相关文章

  1. WPF界面设计技巧(11)-认知流文档 &amp&semi; 小议WPF的野心

    原文:WPF界面设计技巧(11)-认知流文档 & 小议WPF的野心 流文档是WPF中的一种独特的文档承载格式,它的书写和呈现方式都很像HTML,它也几乎具备了HTML的绝大多数优势,并提供了更 ...

  2. WPF界面设计技巧(10)-样式的继承

    原文:WPF界面设计技巧(10)-样式的继承 PS:现在我的MailMail完工了,进入内测阶段了,终于可以腾出手来写写教程了哈,关于MailMail的介绍及内测程序索取:http://www.cnb ...

  3. WPF界面设计技巧(8)—自制山寨版CheckListBox

    原文:WPF界面设计技巧(8)-自制山寨版CheckListBox 近年来IT市场山寨横行啊,我们今天也来发扬一下山寨精神,搞个自制的CheckListBox出来. 喏,CheckListBox 就是 ...

  4. WPF界面设计技巧(7)—模拟电梯升降的缓动动画

    原文:WPF界面设计技巧(7)-模拟电梯升降的缓动动画 如同Flash一样,WPF的亮点之一也在于其擅于表现平滑的动画效果,但以移动动画来说,仅凭简单的起始位置.目标位置,所产生的动画仍会非常生硬,这 ...

  5. WPF界面设计技巧(6)—玩玩数字墨水手绘涂鸦

    原文:WPF界面设计技巧(6)-玩玩数字墨水手绘涂鸦 想让你的程序支持鼠标及手写笔涂鸦吗?只要敲入“<InkCanvas/>”这几个字符,你就会领悟什么叫“很好很强大”,今天我们来做一个手 ...

  6. WPF界面设计技巧(5)—自定义列表项呈现内容

    原文:WPF界面设计技巧(5)-自定义列表项呈现内容 接续上次的程序,稍微改动一下原有样式,并添加一个数据模板,我们就可以达成下面这样的显示功能: 鼠标悬停于文件列表项上,会在工具提示中显示图像缩略图 ...

  7. WPF界面设计技巧(4)—自定义列表项样式

    原文:WPF界面设计技巧(4)-自定义列表项样式 有前面修改按钮样式的基础,我们可以尝试来定制一个即好看又好用的 ListBox ,今天先来讲“好看”部分. 打开 Microsoft Visual S ...

  8. WPF界面设计技巧(3)—实现不规则动画按钮

    原文:WPF界面设计技巧(3)-实现不规则动画按钮 发布了定义WPF按钮的教程后,有朋友问能否实现不规则形状的按钮,今天我们就来讲一下不规则按钮的制作. 不规则按钮的做法实际上和先前我们做不规则窗体的 ...

  9. WPF界面设计技巧(2)—自定义漂亮的按钮样式

    原文:WPF界面设计技巧(2)-自定义漂亮的按钮样式 上次做了个很酷的不规则窗体,这次我们来弄点好看的按钮出来,此次将采用纯代码来设计按钮样式,不需要 Microsoft Expression Des ...

随机推荐

  1. SignalR

    https://msdn.microsoft.com/zh-cn/magazine/dn802609.aspx http://www.asp.net/signalr/overview/getting- ...

  2. 小小收获for python

    包导入问题: 包之外导入:还是按照sys.path的搜索路径进行模块的导入 包内的导入:python3.0+     完全区分绝对导入和相对导入 from . import string     #在 ...

  3. 《大象-Think In UML》读书笔记1

    大音希声,大象希行. 什么是面向过程?什么是面向对象? 面向过程归纳为结构化程序设计.DFD图.ER模型.UC矩阵等,而面向对象则被归纳为继承.封装.多态.复用等具体的技术.事实上,上述的所有技术都只 ...

  4. 鸡和蛋的OO设计

    一个题目:用类图表示出鸡和蛋的关系. 第一版: 第二版: 一个鸡可以下N个蛋,一个蛋可以浮出0或者1个鸡. 问题是公鸡不会下单,第三版:

  5. JQ系列:css操作

    JQ中的 .css()有三种使用方法: $('#p').css('width'); 取得ID为p的样式属性的width值;等同 return width $('#p').css('width','10 ...

  6. HDU 3688 Searchlights(并查集)

    Problem Description There is a piece of grids land of size n×m. Chandler and his team take responsib ...

  7. QT-Demo-Colck-01

    QT += widgets QT += core HEADERS += \ mainwindow.h SOURCES += \ mainwindow.cpp \ main.cpp #ifndef MA ...

  8. CentOS的软件包的管理之rpm和yum

    在linux上,一个软件包通常由二进制程序,库文件,配置文件和帮助文件组成. 其中: 二进制程序一般都放在/bin,/sbin,/usr/bin,/usr/sbin,/usr/local/bin和/u ...

  9. Nginx日志分析及脚本编写

    在我们日常的运维中,当Nginx服务器正常运行后,我们会经常密切关注Nginx访问日志的相关情况,发现有异常的日志信息需要进行及时处理. 那今天我将跟大家一起来研究和分析Nginx日志,nginx默认 ...

  10. 关于golang&period;org&sol;x包问题

    关于golang.org/x包问题 由于谷歌被墙,跟谷歌相关的模块无法通过go get来下载,解决方法: git clone https://github.com/golang/net.git $GO ...