CH03_布局
第3章:布局
本章目标
- 理解布局的原则
- 理解布局的过程
- 理解布局的容器
- 掌握各类布局容器的运用
理解 WPF 中的布局
WPF 布局原则
WPF 窗口只能包含单个元素。为在WPF 窗口中放置多个元素并创建更贴近实用的用户男面,需要在窗口上放置一个容器,然后在这个容器中添加其他元素。造成这一限制的原因是 Window 类继承自 ContentControl 类,在后续章节中将进一步分析ContentControl类。
布局过程
WPF 布局包括两个阶段:测量(measure)阶段和排列(arange)阶段。在测量阶段,容器遍历所有子元素,并询问子元素它们所期望的尺寸。在排列阶段,容器在合适的位置放置子元素。
当然,元素未必总能得到最合适的尺寸—有时容器没有足够大的空间以适应所含的元素。在这种情况下,容器为了适应可视化区域的尺寸,就必须剪裁不能满足要求的元素。在后面可以看到,通常可通过设置最小窗口尺寸来避免这种情况。
注意:
布局容器不能提供任何滚动支持.相反,滚动是由特定的内容控件ScrollViewer—一提供的,ScrollViewer 控件几乎可用于任何地方。
布局容器
所有 WPF 布局容器都是派生自 System.Windows.Controls.Panel 抽象类的面板(见下图)。Panel 类添加了少量成员,包括三个公有属性,下表列出了这三个公有属性的详情。
名称 | 说明 |
---|---|
Background | 该属性是用于为面板背景着色的画刷。如果想接收鼠标事件,就必须将该属性设置为非空值(如果想接收鼠标事件,又不希望显示固定颜色的背景,那么只需要将背景色设置为透明即可) |
Children | 该属性是在面板中存储的条目集合。这是第一级条目—换句话说,这些条目自身也可以包含更多的条目。 |
IsItemsHost | 该属性是一个布尔值,如果面板用于显示与 ItemsControl 控件关联的项(例如,TreeView 控件中的节点或列表框中的列表项),该属性值为 true。在大多数情况下,甚至不需要知道列表控件使用后台面板来管理它所包含的条目的布局。但如果希望创建自定义的列表,以不同方式放置子元素(例如,以平铺方式显示图像的 ListBox控件),该细节就变得很重要了。 |
就Panel基类本身而言没有什么特别的,但它是其他更多特类的起点。WPF提供了大量可用于安排布局的继承自Panel的类,下表中列出了其中几个最基本的类。与所有 WPF控件和大多数可视化元素一样,这些类位于 System. Windows.Controls 名称空间中。
名称 | 说明 |
---|---|
StackPanel | 在水平或垂直的堆栈中放置元素。这个布局容器通常用于更大、更复杂窗口中的一些小区域. |
WrapPanel | 在一系列可换行的行中放置元素。在水平方向上,WrapPanel 面板从左向右放置条目,然后在随后的行中放置元素。在垂直方向上,WrapPanel 面板在自上而下的列中放置元素,并使用附加的列放置剩余的条目. |
DockPanel | 根据容器的整个边界调整元素 |
Grid | 根据不可见的表格在行和列中排列元素,这是最灵活、最常用的容器之一. |
UnitformGrid | 在不可见但是强制所有单元格具有相同尺寸的表中放置元素,这个布局容器不常用. |
Canvas | 使用固定坐标绝对定位元素。这个布局容器与传统 Windows 窗体应用程序最相似,但没有提供锚定或停靠功能。因此,对于尺寸可变的窗口,该布局容器不是合适的选择。如果选择的话,需要另外做一些工作。 |
StackPanel 面板
StackPanel 面板是最简单的布局容器之一。该面板简单地在单行或单列中以堆栈形式放置其子元素。例如,下面的代码段中,窗口包含4个按钮。
<Window x:Class="WpfApp1.Window1"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:WpfApp1"mc:Ignorable="d"Title="Window1" Height="450" Width="800"><StackPanel><Label>A Button Stack</Label><Button>button1</Button><Button>button2</Button><Button>button3</Button><Button>button4</Button></StackPanel>
</Window>
认情况下,StackPane! 面板按自上而下的顺序推列元素,使每个元素的高度适合它的内≥。在这个示例中,这底味老标签和技钮的大小刚好足够适应它们内部包含的文本。所有元素都被拉伸到 SatckPane! 面板的整个宽度,这也是窗口的宽度。如果加宽窗口,StackPanel 面板也会变宽,并且按钮也会拉伸自身以适应变化。
通过设置 Oricntation 属性,StackPanel 面板也可用于水平排列元素:
<Window x:Class="WpfApp1.Window1"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:WpfApp1"mc:Ignorable="d"Title="Window1" Height="450" Width="800"><StackPanel Orientation="Horizontal"><Label>A Button Stack</Label><Button MinWidth="100">button1</Button><Button MinWidth="100">button2</Button><Button MinWidth="100">button3</Button><Button MinWidth="100">button4</Button></StackPanel>
</Window>
布局属性
尽管布局由容器决定,但子元素仍有一定的决定权。实际上,布局面板支持一小组布局属性,以便与子元素结合使用,下表中列出了这些布局属性。
名称 | 说明 |
---|---|
HorizontalAlignment | 前水平方向上新额外的空闲时,该属性决定了子元素在布局容器中如何定位。可选用 Center、Left、 Right 或 Stretch 等属性值。 |
VerticalAlignment | 当垂直方向上有额外的空闲时,该属性决定了子元素在布局容中如何定位。可选用 Center、Top、Bottom 或 Stretch 等属性值。 |
Margin | 该属性用于在元素的周围添加一定的空间.Margin 属性是 System.Windows.Thickness结构的一个实例,该结构具有分别用于为顶部、底部、左边和右边添加空间的独立组件。 |
MinWidth 和 MinHeight | 这两个属性用于设置元素的最小尺寸。如果一个元素对于其他布局容器来说太大,该元素将被剪裁以适合容器。 |
MaxWidth 和 MaxHeight | 这两个属性用于设置元素的最大尺寸。如果有更多可以使用的空间,那么在扩展子元素时就不会超出这一限制,即使将 HorizontalAlignment 和 VerticalAlignment 属性设置为 Stretch 也同样如此。 |
Width 和 Height | 这两个属性用于显式地设置元素的尺寸。这一设置会重写为 HorizontalAlignment 和VerticalAlignment 属性设置的 Stretch 值。但不能超出MinWidth、MinHeight、MaxWidth 和 MaxHeight 属性设置的范。 |
对齐方式
通常,对于 Label 控件,HorizontalAligament 属性的值默认为 Lef:对于 Button 控件,HorzontalAlignment 属性的售默认为 Streteh。这也是为什么每个技钮的宽度被调整为控列的宽度的原因所在。但可以改变这些细节:
<Window x:Class="WpfApp1.Window1"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:WpfApp1"mc:Ignorable="d"Title="Window1" Height="450" Width="800"><StackPanel><Label HorizontalAlignment="Center">A Button Stack</Label><Button HorizontalAlignment="Left">button1</Button><Button HorizontalAlignment="Right">button2</Button><Button>button3</Button><Button>button4</Button></StackPanel>
</Window>
现在前两个按钮的尺寸是它们应当具有的最小尺寸,并进行了对齐,而底部两个按钮被拉伸至整个 SiackPanel面板的宽度。如果改变窗口的尺寸,就会发现标签保持在中间位置,而前两个按钮分别被粘贴到两边。
注意:
SiackPanel面板也有自己的HorizontalAlignment 和 VerticalAlignment 属性。这两个属性职认都被设置为 Stretch,所以 StackPanel 面板完全充满它的容器、在这个示例中,这意味着stackPanel西板充滿整个窗口。如果使用不同设置,StackPanel 面板的尺寸将足够宽以容纳最宽的控件。
边距
在SackPane!示例中,在当前情况下存在一个明显的问题。设计良好的窗口不只是包含元素—还应当在元素之间包貪一定的额外空间。为了添加额外的空间并使StaokPanel 面板示例中的按钮不那么紧密,可为控件设置边距。
当设置边距时,可为所有边设置相同的宽度,如下所示:
<Button Margin="5">button3</Button>
相应地,也可为控件的每个边以左、上、右、下的顺序设置不同的边距:
<Button Margin="5,10,5,10">Button 3</Button>
在代码中,使用 Thickness 结构来设置边距:
btn. Margin = new Thickness (5) ;
为得到正确的控件边距,需要采用一些艺术手歐,因內需要考慮相邻控件边距改置的相互影响。例如,如果两个技钮堆在一起,位于最高处的技钮的底部边距设置为5,而下面技钮的顶部边距也设置为5,那么在这两个按钮之间就有10个单位的空间。
理想情况是,能尽可能始终如一地保持不同的边距设置,避免为不同的边设置不同的值。
例如,在StackPanel示例中,为按钮和面板本身使用相同的边距是比较合适的,如下所示:
<Window x:Class="WpfApp1.Window1"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:WpfApp1"mc:Ignorable="d"Title="Window1" Height="450" Width="800"><StackPanel Margin="5"><Label Margin="3" HorizontalAlignment="Center">A Button Stack</Label><Button Margin="3" HorizontalAlignment="Left">button1</Button><Button Margin="3" HorizontalAlignment="Right">button2</Button><Button Margin="3">button3</Button><Button Margin="3">button4</Button></StackPanel>
</Window>
尺寸设置
最后,每个元素都提供了 Height 和 Width 属性,用于显式地指定元素大小。但这种设置一般不是一个好主意。相反,如有必要,应当使用最大尺寸和最小尺寸属性,将控件限制在正确范围内。
提示:
在WPF中显式地设置尺寸之前一定要三思。在良好的布局设计中,不必显式地设置尺寸.
如果确实添加了尺寸信息,那就冒险创建了一种更不稳定的布局,这种布局不能适应变化(例如,不能适应不同的语言和不同的窗口尺寸),而且可能剪裁您的内容.
例如,您可能决定拉伸 StackPanel 容器中的按钮,使其适合 StackPanel,但其宽度不能超过200单位,也不能小于100单位(默认情况下,最初按钮的最小宽度是75单位)。
<Window x:Class="WpfApp1.Window1"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:WpfApp1"mc:Ignorable="d"Title="Window1" Height="450" Width="800"><StackPanel Margin="5"><Label Margin="3" HorizontalAlignment="Center">A Button Stack</Label><Button Margin="3" MaxWidth="200" MinWidth="100">button1</Button><Button Margin="3" MaxWidth="200" MinWidth="100">button2</Button><Button Margin="3" MaxWidth="200" MinWidth="100">button3</Button><Button Margin="3">button4</Button></StackPanel>
</Window>
当 StackPanel 调整按钮的尺寸时,需要考虑以下几部分信息:
- 最小尺寸: 每个按钮的尺寸始终不能小于最小尺寸。
- 最大尺寸: 每个按钮的尺寸始终不能超过最大尺寸(除非执行错误操作,使最大尺寸比最小尺寸还小)
- 内容: 如果按钮中的内容需要更大的宽度,StackPanel 容器会尝试扩展技钮(可以通过检查 DesiredSized 属性确定所需的按钮大小,该属性返回最小宽度或内容的宽度,返回两者中较大的那个)。
- 容器尺寸: 如果最小宽度大于 StackPanel 面板的宽度,按钮的一部分将被剪裁掉。否则,不允许按钮比 StackPanel 面板更宽,即使不能适合按钮表面的所有文本也同样如此。
- 水平对齐方式: 因为默认情况下按钮的 HorizontalAlignment 属性值设置为Stretch,所以 StackPanel 面板将尝试放大按钮以占满 StackPanel 面板的整个宽度。
Border 控件
Border控件不是布局面板,而是非常便于使用的元素,经常与布局面板一起使用。所以,在继续介绍其他布局面板之前,现在先介绍一下 Border 控件是有意义的。
Border 类非常简单。它只能包含一段嵌套内容(通常是布局面板),并为其添加背景或在其周围添加边框。为了深入地理解Border 控件,只需要掌握下表中列出的属性就可以了。
名称 | 说明 |
---|---|
Barckground | 使用Brush 对象设置边框中所有内容后面的背景。可使用固定颜色背景,也可使用其他更特殊的背景. |
BorderBush和BorderThickness | 使用Brush 对象设置位于Border 对象边缘的边框的颜色,并设置边框的宽度。为显示边框,必须设置这两个属性. |
CornerRadius | 该属性可使边框具有雅致的圆角。ComerRadius 的值越大,圆角效果就越明显. |
Padding | 该属性在边框和内部的内容之间添加空间(与此相对,Margin 属性在边框之外添加空间). |
下面是一个具有轻微圆角效果的简单边框,该边框位于一组按钮的周围,这组按钮包含在一个StackPanel 面板中:
<Window x:Class="WpfApp1.Window1"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:WpfApp1"mc:Ignorable="d"Title="Window1" Height="450" Width="800"><Border Margin="5" Padding="5" Background="LightYellow"BorderBrush="SteelBlue" BorderThickness="3,3,3,5" CornerRadius="3"VerticalAlignment="Top"><StackPanel ><Button Margin="3">button1</Button><Button Margin="3">button2</Button><Button Margin="3">button3</Button></StackPanel></Border>
</Window>
WrapPanel 和 DockPanel 面板
WrapPanel 面板
WrapPanel 面板在可能的空间中,以一次一行或一列的方式布置控件。默认情况下,WrapPanel.Orientation 属性设置为 Horizontal;控件从左向右进行排列,再在下一行中排列。但可将 WrapPanel.Orientation 属性设置为 Vertical,从而在多个列中放置元素。
提示:
与StackPanel 面板类似,WrapPanel 面板实际上主要用来控制用户界面中一小部分的布局细节,并非用于控制整个窗口布局。例如,可能使用 WrapPanel面板以类似工具栏控件的方式将所有按钮保持在一起。
<Window x:Class="WpfApp1.Window1"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:WpfApp1"mc:Ignorable="d"Title="Window1" Height="450" Width="800"><WrapPanel Margin="3"><Button VerticalAlignment="Top">Button1</Button><Button MinHeight="60">Button2</Button><Button VerticalAlignment="Bottom">Button3</Button><Button>Button4</Button><Button VerticalAlignment="Center">Button5</Button></WrapPanel></Window>
注意:
WrapPanel 面板是唯一一个不能通过灵活使用Grid 面板代替的面板。
DockPanel 面板
DockPanel 面板是更有趣的布局选项。它沿着一条外边缘来拉伸所包含的控件。理解该面板最简便的方法是,考虑一下位于许多 Windows 应用程序窗口顶部的工具栏。这些工具栏停靠到窗口顶部。与 StackPanel 面板类似,被停靠的元素选择它们布局的一个方面。例如,如果将一个按钮停靠在DockPanel 面板的顶部,该按钮会被拉伸至 DockPanel 面板的整个宽度,但根据内容和 MinHfeight 属性为其设置所需的高度。而如果将一个按钮停靠到容器左边,该技钮的高度将被拉伸以适应容器的高度,而其宽度可以根据需要自由增加。
案例1:
<Window x:Class="WpfApp1.Window1"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:WpfApp1"mc:Ignorable="d"Title="Window1" Height="450" Width="800"><!--LastChildFill:最后一个子元素填充--><DockPanel LastChildFill="True"><Button DockPanel.Dock="Top">上</Button><Button DockPanel.Dock="Bottom">下</Button><Button DockPanel.Dock="Left">左</Button><Button DockPanel.Dock="Right">右</Button><Button>中间</Button></DockPanel></Window>
案例2:
<Window x:Class="WpfApp1.Window1"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:WpfApp1"mc:Ignorable="d"Title="Window1" Height="450" Width="800"><!--DockPanel.Dock:停靠方向LastChildFill:最后一个子元素填充HorizontalAlignment:水平对齐方式MinWidth:最小宽度--><DockPanel LastChildFill="True"><Button DockPanel.Dock="Top">上-1</Button><Button DockPanel.Dock="Top" HorizontalAlignment="Center" MinWidth="200">上-2</Button><Button DockPanel.Dock="Top" HorizontalAlignment="Left" MinWidth="200">上-3</Button><Button DockPanel.Dock="Bottom">下</Button><Button DockPanel.Dock="Left">左</Button><Button DockPanel.Dock="Right">右</Button><Button>中间</Button></DockPanel></Window>
嵌套布局容器
很少单独使用 StackPanel、WrapPanel 和 DockPanel 面板。相反,它们通常用来设置一部分用户界面的布局。例如,可使用 DockPanel 面板在窗口的合适区域放置不同的 StackPanel 和WrapPane! 面板容器。
案例1:
<Window x:Class="WpfApp1.Window1"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:WpfApp1"mc:Ignorable="d"Title="Window1" Height="450" Width="800"><!--LastChildFill:最后一个子元素填充DockPanel.Dock:停靠方向HorizontalAlignment:水平对齐方式Orientation:排列方向(水平/垂直)Margin:外边距Padding:内边距--><DockPanel LastChildFill="True"><StackPanel DockPanel.Dock="Bottom" HorizontalAlignment="Right" Orientation="Horizontal"><Button Margin="10,10,2,10" Padding="3">OK</Button><Button Margin="2,10,10,10" Padding="3">Cancel</Button></StackPanel><TextBox DockPanel.Dock="Top">这是一个文本框</TextBox></DockPanel></Window>
提示:
如果有一棵茂密的嵌套元素树,很可能看不到整个结构。Visual Studio 提供了一个方使的功能,用于显示一棵表示各个元素的树,并允许您通过逐步单击进入希望查看(或修改)的元素。
这一功能是指 Document Outline 窗口,可通过选择 View | Other Windows | Document Outline 菜单项来显示该窗口。
Grid 面板
Grid 面板是WPF 中功能最强大的布局容器。很多使用其他布局控件能完成的功能,用Grid面板也能实现。Grid 面板也是将窗口分割成(可使用其他面板进行管理的)更小区域的理想工具。实际上,由于 Grid 面板十分有用,因此在 Visual Studio 中为窗口添加新的XAML 文档时,会自动添加 Grid 标签作为顶级容器,并嵌套在 Window 根元素中。
Grid 面板将元素分隔到不可见的行列网格中。尽管可在一个单元格中放置多个元素(这时这些元素会相互重叠),但在每个单元格中只放置一个元素通常更合理。当然,在Grid 单元格中的元素本身也可能是另一个容器,该容器组织它所包含的一组控件。
提示:
尽管Grid面板被设计成不可见的,但可将 Grid.ShowGridlines 属性设置汐 true,从而更清晰她观察Gird 面板。这一特性并不是真正试图美化窗口,反而是为了方便调试,设计该特性旨在帮助理解 Grid 面板如何将其自身分制成多个较小的区域。这一特性十分童要,因为通过该特性可准确控制 Grid 面板如何选择列宽和行高。
需要两个步骤来创建基于 Crd 面板的布局。首先,选择希望使用的行和列的数厭。然后,为每个包含的元素指定恰当的行和列,从而在合适的位置放置元素。
Grid 面板通过使用对象填充 Grid.ColumnDefinitions和 Grid. Row Definiti ons 集合来创建网格和行。例如,如果确定需要两行和三列,可添加以下标签:
<Window x:Class="WpfApp1.Window1"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:WpfApp1"mc:Ignorable="d"Title="Window1" Height="450" Width="800"><Grid ShowGridLines="True"><!--行--><Grid.RowDefinitions><RowDefinition/><RowDefinition/></Grid.RowDefinitions><!--列--><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions></Grid></Window>
为在单元格中放置各个元素,需要使用 Row 和Columm 附加属性。这两个属性的值都是从0开始的索引数。例如,以下标记演示了如何创建Grid面板,并使用按钮填充Grid 面板的部分单元格。
此处存在例外情况。如果不指定 Grid Row 属性,Grid 面板会假定该属性的值为0。对于Crid. Column 属性也是如此。因此,在 Grid 面板的第一个单元格中放置元素时可不指定这两个属性。
案例1:
<Window x:Class="WpfApp1.Window1"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:WpfApp1"mc:Ignorable="d"Title="Window1" Height="450" Width="800"><Grid ShowGridLines="True"><!--行--><Grid.RowDefinitions><RowDefinition/><RowDefinition/></Grid.RowDefinitions><!--列--><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><Button Grid.Row="0" Grid.Column="0">button1-1</Button><Button Grid.Row="0" Grid.Column="1">button1-2</Button><Button Grid.Row="1" Grid.Column="1">button2-2</Button><Button Grid.Row="1" Grid.Column="2">button2-3</Button></Grid></Window>
调整行和列
Grid 面板支持以下三种设置尺寸的方式:
-
绝对设置尺寸方式: 使用设备无关单位准确地设置尺寸。这是最无用的策略,因为这种策略不够灵活,难以适应内容大小和容器大小的改变,而且难以处理本地化。
-
自动设置尺寸方式: 每行和每列的尺寸刚好满足需要。这是最有用的尺寸设置方式。
-
按比例设置尺寸方式。按比例将空间分割到一组行和列中。这是对所有行和列的标准设置。
可通过将ColumnDefinition 对象的Width 属性或 RowDefinition 对象的 Height 属性设置为数值来确定尺寸设置方式。例如,下面的代码显示了如何设置100 设备无关单位的绝对宽度。
<ColumnDefinition Width="100"></ColumnDefinition>
为使用自动尺寸设置方式,可使用Auto值:
<ColumnDefinition Width="Auto"></ColumnDefinition>
最后,为了使用按比例尺寸设置方式,需要使用*号:
<ColumnDefinition Width="*"></ColumnDefinition>
如果希望不均匀地分割剩余空间,可指定权重,权重必须放在星号之前。例如,如果有两行是按比例设置尺寸,并希望第一行的高度是第二行高度的一半,那么可以使用如下设置来分配剩余空间:
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="2*"></RowDefinition>
案例1:
<Window x:Class="WpfApp1.Window1"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:WpfApp1"mc:Ignorable="d"Title="Window1" Height="450" Width="800"><Grid ShowGridLines="True"><!--行--><Grid.RowDefinitions><RowDefinition Height="*"/><RowDefinition Height="Auto"/></Grid.RowDefinitions><!--HorizontalAlignment:水平对齐方式Orientation:排列方向Margin:外边距--><TextBox Margin="10" Grid.Row="0">这是一个文本框</TextBox><StackPanel Grid.Row="1" HorizontalAlignment="Right" Orientation="Horizontal"><Button Margin="10,10,2,10">OK</Button><Button Margin="2,10,10,10">Cancel</Button></StackPanel></Grid></Window>
跨越行和列
您已经看到如何使用 Row 和 Calum 附加属性在单元格中放置元素。还可以使用另外两个附加属性使元素跨越多个单元格,这两个附加属性是 RowSpan和ColurmSpan。这两个属性使用元素将会占有的行数和列数进行设置。
例如,下面的按钮将占据第一行中的第一个和第二个单元格的所有空间:
<Button Grid.Row="0" Grid.Column="0" Grid.RowSpan="2">跨行</Button>
下面的代码通过跨越两列和两行,拉伸按钮使其占据所有4个单元格:
<Button Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Grid.ColumnSpan="2">跨行并跨列</Button>
案例1:
<Window x:Class="WpfApp1.Window1"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:WpfApp1"mc:Ignorable="d"Title="Window1" Height="450" Width="800"><Grid UseLayoutRounding="True" ><Grid.RowDefinitions><RowDefinition Height="*"/><RowDefinition Height="Auto"/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="*"/><ColumnDefinition Width="Auto"/><ColumnDefinition Width="Auto"/></Grid.ColumnDefinitions><TextBox Margin="10" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3">这是一个文本框</TextBox><Button Margin="10,10,2,10" Padding="3" Grid.Row="1" Grid.Column="1">OK</Button><Button Margin="2,10,10,10" Padding="3" Grid.Row="1" Grid.Column="2">Cancel</Button></Grid></Window>
分割窗口
每个 Windows 用户都见过分割条一能将窗口的一部分与另一部分分离的可拖动分割器,
例如,当使用Windows 资源管理器时,会看到一系列立件实(在左边)和一系列文件(在右边)、可拖动它们之间的分割条来确定每部分占据窗口的比例。
理解如何使用 GridSplitter 类,从而得到所期望的效果需要一定的经验。下面列出几条指导原则:
- GrdSpliter 对象必须放在Grid 单元格中。可与已经存在的内容一并放到单元格中,这时循要调整边距设置,使它们不相互重叠。更好的方法是预留一列或一行专门用于放置 Gridspliter对象,并将预留行或列的Heigh 或 Width 属性的值设置为 Auto。
- Gridspliter 对象总是改变整行或整列的尺寸(而非改变单个单元格的尺寸)。为使Cridspliter对象的外观和行为保持一致,需要拉伸Gridsplitter 对象使其穿越整行或整列,而不是将其限制在单元格中。为此,可使用前面介绍过的RowSpan或ColumnSpan 属性。
- 最初,GridSpliter 对象很小不易看见。为了使其更可用,需要为其设置最小尺寸。对于竖直分割条,需要将 VericalAlignment 属性设置为stretch(使分割条填满区域的整个高度),并将 Width 设置为固定值(如10个设备无关单位)。对于水平分割条,需要设置 HorizontalAlignmeat 属性来拉伸,并将 Height 属性设置为固定值。
- Gridspliter 对齐方式还决定了分割条是水平的(用于改变行的尺寸)还是竖直的(用于改变列的尺寸)。对于水平分割条,需要将 VerticalAlignment 属性设置为Center(这也是默认值),以指明拖动分割条改变上面行和下面行的尺寸。对于竖直分割条,需要将 HorizontalAlignment 属性设置为 Center,以改变分割条两侧列的尺寸。
案例1:
<Window x:Class="WpfApp1.Window1"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:WpfApp1"mc:Ignorable="d"Title="Window1" Height="450" Width="800"><Grid UseLayoutRounding="True" ><!--行设置--><Grid.RowDefinitions><RowDefinition/><RowDefinition/></Grid.RowDefinitions><!--列设置--><Grid.ColumnDefinitions><ColumnDefinition MinWidth="100"/><ColumnDefinition Width="Auto"/><ColumnDefinition MinWidth="50"/></Grid.ColumnDefinitions><!--按钮--><Button Grid.Row="0" Grid.Column="0" Margin="3">left-1</Button><Button Grid.Row="0" Grid.Column="2" Margin="3">right-1</Button><Button Grid.Row="1" Grid.Column="0" Margin="3">left-2</Button><Button Grid.Row="1" Grid.Column="2" Margin="3">right-1</Button><!--分割线--><!--ShowsPreview:是否显示预览--><GridSplitter Grid.Row="0" Grid.Column="1" Grid.RowSpan="2" Width="3" VerticalAlignment="Stretch" HorizontalAlignment="Center" ShowsPreview="False"></GridSplitter></Grid></Window>
上面的标记还包含了一处额外的细节。在声明GridSplitter 对象时,将 ShowsPreview 属性设置为 false .因此,当把分割线从一边拖到另一边时,会立即改变列的尺寸。但是如果将 ShowsPreview 属性设置为 true,当拖动分割条时就会看到一个灰色的阴影跟随鼠标指针,用于显示将在何处进行分割。并且直到释放了鼠标键之后列的尺寸才改变。如果GridSplitter 对象获得了焦点,可可以使用箭头改变相应的尺寸。
如果希望分割条以更大的幅度(如每次10个单位)进行移动,可调整DragIncrement 属性。
提示:
可以改变 GridSplitter 对象的填充方式,使其不只是具有阴影的灰色矩形。技巧是使用Background 属性应用填充,该属性接受简单的颜色或更复杂的画刷。
Grid 面板通常包含多个 GridSpliter 对象。然而,可以在一个 Grid 面板中嵌套另一个Grid面板;而且,如果确实在 Grid 面板中嵌套了Grid 面板,那么每个Grid 面板可以有自己的GridSplitter对象。这样就可以创建被分割成两部分(如左边窗格和右边窗格)的窗口,然后将这些区域(如右边的窗格)进一步分成更多的部分(例如,可调整大小的上下两部分)。
案例2:
<Window x:Class="WpfApp1.Window1"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:WpfApp1"mc:Ignorable="d"Title="Window1" Height="450" Width="800"><Grid UseLayoutRounding="True" ><!--列设置:3列--><Grid.ColumnDefinitions><ColumnDefinition MinWidth="100"/><ColumnDefinition Width="Auto"/><ColumnDefinition MinWidth="50"/></Grid.ColumnDefinitions><!--左侧Grid--><Grid Grid.Column="0"><!--行设置:2行--><Grid.RowDefinitions><RowDefinition/><RowDefinition/></Grid.RowDefinitions><Button Margin="3" Grid.Row="0">Top Left</Button><Button Margin="3" Grid.Row="1">Bottom Left</Button></Grid><!--分割线--><!--ShowsPreview:是否显示预览--><GridSplitter Grid.Column="1" Grid.RowSpan="2" Width="3" VerticalAlignment="Stretch" HorizontalAlignment="Center" ShowsPreview="False"></GridSplitter><!--右侧Grid--><Grid Grid.Column="2"><!--行设置:3行--><Grid.RowDefinitions><RowDefinition/><RowDefinition Height="Auto"/><RowDefinition/></Grid.RowDefinitions><Button Margin="3" Grid.Row="0">Top Right</Button><Button Margin="3" Grid.Row="2">Bottom Right</Button><GridSplitter Grid.Row="1" Height="3" VerticalAlignment="Center" HorizontalAlignment="Stretch" ShowsPreview="False"></GridSplitter></Grid></Grid></Window>
共享尺寸组
正如在前面看到的,Grid 面板包含一个行列集合,可以明确地按比例确定行和列的尺寸,或根据其子元素的尺寸确定行和列的尺寸。还有另一种确定一行或一列尺寸的方法—与其他行或列的尺寸相匹配。这是通过称为“共享尺寸组”(Shared size groups)的特性实现的。
共享尺寸组的目标是保持用户界面独立部分的一致性。例如,可能希望改变一列的尺寸以适应其内容,并改变另一列的尺寸使其与前面一列改变后的尺寸相匹配。然而,共享尺寸组的真正优点是使独立的Grid 控件具有相同的比例。
案例1:
<Window x:Class="WpfApp1.Window1"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:WpfApp1"mc:Ignorable="d"Title="Window1" Height="450" Width="800"><Grid Grid.IsSharedSizeScope="True" Margin="3"><!--设置行:3行--><Grid.RowDefinitions><RowDefinition/><RowDefinition Height="auto"/><RowDefinition/></Grid.RowDefinitions><!--上方Grid--><Grid Margin="3" Background="LightYellow" ShowGridLines="True"><!--设置列:3列--><!--SharedSizeGroup:共享尺寸组--><Grid.ColumnDefinitions><ColumnDefinition Width="auto" SharedSizeGroup="TextLabel"/><ColumnDefinition Width="auto"/><ColumnDefinition/></Grid.ColumnDefinitions><Label Margin="5" Grid.Column="0">这是一个长的文本</Label><Label Margin="5" Grid.Column="1">其他文本</Label><TextBox Margin="5" Grid.Column="2">这是一个文本框</TextBox></Grid><!--中间标签--><Label Grid.Row="1">这是中间的标签</Label><!--下方Grid--><Grid Grid.Row="2" Margin="3" Background="LightCoral" ShowGridLines="True"><!--设置列:2列--><!--SharedSizeGroup:共享尺寸组--><Grid.ColumnDefinitions><ColumnDefinition Width="auto" SharedSizeGroup="TextLabel"/><ColumnDefinition/></Grid.ColumnDefinitions><Label Margin="5" Grid.Column="0">短的</Label><TextBox Margin="5" Grid.Column="1">这是一个文本框</TextBox></Grid></Grid></Window>
UnitformGrid 面板
有一种网格不遵循前面讨论的所有原则–UniformGrid 面板。与Grid 面板不同,UaifommCrid 面板不需要(甚至不支持)预先定义的列和行。相反,通过简单地设置Rows 和Colurs 属性来设置其尺寸。每个单元格始终具有相同的大小,因为可用的空间被均分。最后,元素根据定义的顺序被放置到适当的单元格中。UniformGrid 面板中没有 Row和 Column 附加属性,也没有空白单元格。
案例1:
<Window x:Class="WpfApp1.Window1"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:WpfApp1"mc:Ignorable="d"Title="Window1" Height="450" Width="800"><!--Rows:行数Columns:列数--><UniformGrid Rows="2" Columns="2"><Button>Top Left</Button><Button>Top Right</Button><Button>Buttom Left</Button><Button>Buttom Right</Button></UniformGrid></Window>
Canvas 面板
Canvas 面板允许使用精确的坐标放潭元案,如果设计数据驱动的富窗体和标准对话框,这并非好的选择;但如果需要构建其他一些不同的内容(例如,为图形工具创建绘图表面),Canvas 面板可能是个有用的工具。Canvas面板还是最轻量级的布局容器。这是因为 Canvas面板没有包含任何复杂的布局逻辑,用以改变其子元素的首选尺寸。Canvas 面板只是在指定的位置放置其子元素,并且其子元素具有所希望的精确尺寸。
为在 Canvas 面板中定位元素,需要设置 Canvas.Left 和 Canvas,Top 附加属性。Canvas.Left 属性设置元素左边和 Canvas 面板左边之间的单位数,Canvas.Top 属性设置子元素顶边和Canvas 面板顶边之间的单位数。同样,这些数值也是以设备无关单位设置的,当将系统DPI设置为 96 dpi 时,设备无关单位恰好等于通常的像素。
注意:
另外,可使用 Canvas.Right 属性而不是 Canvas.Lef 属性来确定元素和 Canvas 面板右边缘间的距离;可使用 Canvas.Bottom 属性而不是 Canvas.Top 属性来确定元素和 Canvas 面板底部边缘的距离。不能同时使用 Canvas.Right 和 Canvas. Left 属性,也不能同时使用 Canvas.Top 和Canvas.Bottom 属性。
案例1:
<Window x:Class="WpfApp1.Window1"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:WpfApp1"mc:Ignorable="d"Title="Window1" Height="450" Width="800"><!--Canvas.Left: 左边距Canvas.Top: 上边距Width: 宽度Height: 高度--><Canvas><Button Canvas.Left="10" Canvas.Top="10">(10,10)</Button><Button Canvas.Left="120" Canvas.Top="30">(120,30)</Button><Button Canvas.Left="60" Canvas.Top="80" Width="50" Height="50">(60,80)</Button><Button Canvas.Left="70" Canvas.Top="120" Width="100" Height="50">(70,120)</Button></Canvas></Window>
Z 轴坐标
如果 Canvas 面板中有多个互相重叠的元素,可通过设置Canvas ZIndex 附加属性来控制它们的层叠方式。
添加的所有元素通常都具有相同的 Zlndex 值—0。如果元素具有相同的 ZIndex 值,就按它们在Canvas.Children 集合中的顺序进行显示,这个顺序依赖于元素在 XAMIL 标记中定义的顺序。
lnkCanvas 元素
WPF 还提供了 InkCanvas 元素,它与 Canvas 面板在某些方面是类似的(而在其他方面却完全不同)。和 Canvas 面板一样,InkCanvas 元素定义了4个附加属性(Top、Left、Bottom 和 Righn),可将这4个附加属性应用于子元素,以根据坐标进行定位。然而,基本的内容区别很大—零际上,InkCanvas 类不是派生自 Canvas类,甚至也不是派生自 Pane! 基类,而是直接派生自FrameworkElement类。
InkCanvas元素的主要目的是用于接收手写笔输入。手写笔是一种在平板 PC 中使用的类似于钢笔的输入设备,然而,InkCanvas 元素同时也可使用鼠标进行工作,就像使用手写笔一样。因此,用户可使用鼠标在 InkCanvas 元素上绘制线条,或者选择以及操作 InkCanvas 中的元素。
InkCanvas 元素实际上包含两个子内容集合。一个是为人熟知的Children集合,它保存任意元素,就像 Canvas 面板一样。每个子元素可根据Top、Lef、Bottom 和 Right属性进行定位。另一个是Strokes 集合,它保存 System.Windows.Ink.Stroke 对象,该对象表示用户在 InkCanvas。元素上绘制的图形输入。用户绘制的每条直线或曲线都变成独立的 Stroke 对象。得益于这两个集合,可使用 InkCanvas 让用户使用存储在 Strokes 集合中的笔画(stroke)为保存在Children 集合中的内容添加注释。
根据为 EditingMode 属性设置的值,可以采用截然不同的方式使用 InkCanvas 元素。下表列出了所有选项:
名称 | 说明 |
---|---|
Ink | InkCanvas 元素允许用户绘制批注,这是默认模式。当用户用鼠标或手写笔绘图时,会绘制笔画. |
GestureOnly | InkCanvas 元素不允许用户绘制笔画批注,但会关注预先定义的特定姿势(例如在某个方向拖动手写笔或涂画内容)•能识别的姿势的完整列表由 System.Windows. Ink.Application Gesture 枚举给出. |
InkAndGesture | InkCanvas元素允许用户绘制笔画批注,也可以识别预先定义的姿势. |
EraseByStroke | 当单击笔画时,InkCanvas 元素会擦除笔画。如果用户使用手写笔,可使用手写笔的底端切换到该模式(可使用只读的 ActiveEditingMode 属性确定当前编辑模式,也可通过改变EditingModelinverted 属性来改变手写笔的底端使用的工作模式) |
EraseByPoint | 当单击笔画时,InkCanvas 元素会擦除笔画中被单击的部分(笔画上的一个点) |
Select | InkCanvas 面板允许用户选择保存在Children集合中的元素。要选择一个元素,用户必须单击该元素或拖动“套索”选择该元素。一旦选择一个元素,就可以移动该元素、改变其尺寸或将其删除 |
None | InkCanvas 元素忽略鼠标和手写笔输入。 |
案例1:
<Window x:Class="WpfApp1.Window1"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:WpfApp1"mc:Ignorable="d"Title="Window1" Height="450" Width="800"><InkCanvas Name="inkCanvas" Background="LightYellow" EditingMode="Ink"></InkCanvas></Window>
inkCanvas 元素会引发多种事件,当编辑模式改变时会引发 ActiveEditingModeCbanged 事件,在 GestureOnly 或 InkAndGesture 模式下删除姿势时会引发Gesture 事件,绘制完笔画时会引发SrokeColleoted 事件,擦除笔画时会引发 StokeErasing 事件和StrokeErased 事件,在 Select 模式下选择元素或改变元素时会引发 SelectionChanging 事件、SelectionChanged 事件、SelectionMoving 事件、SelectionMoved 事件、SelectionResizing 事件和 SelectionResized 事件。其中,名称以 “ing”结尾的事件表示动作将要发生,但可以通过设置 EventATgs 对象的Cancel属性取消事件。
在Select 模式下,InkCanvas 元素可为拖动以及操作内容提供功能强大的设计界面。下图显示了 InkCanvas 元素中的一个按钮控件,左图中显示的是该按钮被选中的情况,而右图中显示的是选中该按钮后,改变其位置和尺寸的情况。
案例2:
<Window x:Class="WpfApp1.Window1"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:WpfApp1"mc:Ignorable="d"Title="Window1" Height="450" Width="800"><InkCanvas Name="inkCanvas" Background="LightYellow" EditingMode="Select"><Button InkCanvas.Top="20" InkCanvas.Left="50">hello</Button></InkCanvas></Window>
布局示例
列设置
布局容器(如Grid面板)使得窗口创建整个布局结构变得非常容易。例如下图中显示的窗口及设置。该窗口在一个表格结构中排列各个组件–标签、文本框以及按钮。
案例1:
<Window x:Class="WpfApp1.Window1"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:WpfApp1"mc:Ignorable="d"Title="Window1" Height="450" Width="800"><Grid Margin="3,3,10,3" ShowGridLines="False"><!--行设置--><Grid.RowDefinitions><RowDefinition Height="auto"/><RowDefinition Height="auto"/><RowDefinition Height="auto"/><RowDefinition Height="auto"/></Grid.RowDefinitions><!--列设置--><Grid.ColumnDefinitions><ColumnDefinition Width="auto"/><ColumnDefinition Width="*"/><ColumnDefinition Width="auto"/></Grid.ColumnDefinitions><Label Grid.Row="0" Grid.Column="0" Margin="3" VerticalAlignment="Center">Home:</Label><TextBox Grid.Row="0" Grid.Column="1" Margin="3" Height="auto" VerticalAlignment="Center">c:\</TextBox><Button Grid.Row="0" Grid.Column="2" Margin="3" Padding="2">Browser</Button><Label Grid.Row="1" Grid.Column="0" Margin="3" VerticalAlignment="Center">Network:</Label><TextBox Grid.Row="1" Grid.Column="1" Margin="3" Height="auto" VerticalAlignment="Center">e:\work</TextBox><Button Grid.Row="1" Grid.Column="2" Margin="3" Padding="2">Browser</Button><Label Grid.Row="2" Grid.Column="0" Margin="3" VerticalAlignment="Center">Web:</Label><TextBox Grid.Row="2" Grid.Column="1" Margin="3" Height="auto" VerticalAlignment="Center">c:\</TextBox><Button Grid.Row="2" Grid.Column="2" Margin="3" Padding="2">Browser</Button><Label Grid.Row="3" Grid.Column="0" Margin="3" VerticalAlignment="Center">Secondary:</Label><TextBox Grid.Row="3" Grid.Column="1" Margin="3" Height="auto" VerticalAlignment="Center">c:\</TextBox><Button Grid.Row="3" Grid.Column="2" Margin="3" Padding="2">Browser</Button></Grid></Window>
动态内容
在以下示例中,用户界面可选择短文本和长文本。当使用长文本时,包含文本的按钮会自动改变其尺寸,而其它内容也会相应的调整位置。并且因为改变了尺寸的按钮共享同一布局容器,所以整个用户界面都会改变尺寸。最终的结果是所有按钮保持一致的尺寸—最大按钮的尺寸。
案例1:
xaml代码:
<Window x:Class="WpfApp1.Window1"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:WpfApp1"mc:Ignorable="d"Title="Window1" Height="450" Width="800"><Grid><!--行设置--><Grid.RowDefinitions><RowDefinition Height="*"/><RowDefinition Height="auto"/></Grid.RowDefinitions><!--列设置--><Grid.ColumnDefinitions><ColumnDefinition Width="auto"></ColumnDefinition><ColumnDefinition Width="*"></ColumnDefinition></Grid.ColumnDefinitions><StackPanel Grid.Row="0" Grid.Column="0"><Button x:Name="cmdPrev" Margin="10,10,10,3">Prev</Button><Button x:Name="cmdNext" Margin="10,3,10,3">Next</Button><CheckBox x:Name="chkLong" Margin="10,10,10,10" Unchecked="chkLong_Unchecked" Checked="chkLong_Checked" >Show Long Text</CheckBox></StackPanel><TextBox Grid.Row="0" Grid.Column="1" Grid.RowSpan="2" Margin="0,10,10,10" TextWrapping="WrapWithOverflow">Computer viruses are artificially created programs that are destructive, infectious, and latent, causing damage to computer information or systems. It does not exist independently, but is hidden within other executable programs. After being infected with a virus in a computer, it can affect the running speed of the machine, and in severe cases, it can cause system crashes and damage; Therefore, viruses cause significant losses to users, and typically, these destructive programs are referred to as computer viruses</TextBox><Button Grid.Row="1" Grid.Column="0" Name="cmdClose" Margin="10,3,10,10">Close</Button></Grid>
</Window>
c#代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;namespace WpfApp1
{/// <summary>/// Window1.xaml 的交互逻辑/// </summary>public partial class Window1 : Window{public Window1(){InitializeComponent();}private void chkLong_Checked(object sender, RoutedEventArgs e){this.cmdPrev.Content = "<--Go to the previous Window";this.cmdNext.Content = "Go to Next Window-->";}private void chkLong_Unchecked(object sender, RoutedEventArgs e){this.cmdPrev.Content = "Prev";this.cmdNext.Content = "Next";}}
}
组合式用户界面
许多布局容器(如 StackPanel 面板、DockPanc!面板以及 WrapPanel 面板)可以采用灵活多变的柔性方式非常得体地将内容安排到可用窗口空间中。该方法的优点是,它允许创建真正的组合式界面。换句话说,可在用户界面中希望显示的恰当部分插入不同的面板,而保留用户界面的其他部分。整个应用程序本身可以相应地改变界面,这与Web 门户站点有类似之处。
下图展示了一个组合式用户界面,在一个WrapPanel 面板中放置几个独立的面板。用户可以通过窗口顶部的复选框,选择显示这些面板中的哪些面板。
视图代码:
<Window x:Class="WpfApp1.Window1"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:WpfApp1"mc:Ignorable="d"Title="Window1" Height="450" Width="700"><Grid><Grid.RowDefinitions><RowDefinition Height="auto"/><RowDefinition Height="*"/></Grid.RowDefinitions><StackPanel Grid.Row="0" Margin="3" Background="LightYellow" Orientation="Horizontal"><CheckBox Name="chb1" IsChecked="True" Click="CheckBox_Click">Panel1</CheckBox><CheckBox Name="chb2" IsChecked="True" Click="CheckBox_Click">Panel2</CheckBox><CheckBox Name="chb3" IsChecked="True" Click="CheckBox_Click">Panel3</CheckBox><CheckBox Name="chb4" IsChecked="True" Click="CheckBox_Click">Panel4</CheckBox></StackPanel><WrapPanel Name="container" Grid.Row="1" Background="LightBlue"><Grid MinWidth="200" Name="pnl1"><Grid.RowDefinitions><RowDefinition/><RowDefinition/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><Button Grid.Row="0" Grid.Column="0" MinWidth="50" MinHeight="50" Margin="10">1</Button><Button Grid.Row="0" Grid.Column="1" MinWidth="50" MinHeight="50" Margin="10">2</Button><Button Grid.Row="1" Grid.Column="0" MinWidth="50" MinHeight="50" Margin="10">3</Button><Button Grid.Row="1" Grid.Column="1" MinWidth="50" MinHeight="50" Margin="10">4</Button></Grid><TabControl MinWidth="400" Name="pnl2"><TabItem Header="Page1" VerticalAlignment="Center" HorizontalAlignment="Center"><Label>内容1</Label></TabItem><TabItem Header="Page2"><Label>内容2</Label></TabItem></TabControl><StackPanel Width="200" Name="pnl3"><Label>计算机病毒是人为制造的,有破坏性,又有传染性和潜伏性的,对计算机信息或系统起破坏作用的程序。</Label><Button Width="80" Margin="5,40,5,5">Ok</Button><Button Width="80" Margin="5,5,5,5">Cancel</Button></StackPanel><Grid MinWidth="200" Name="pnl4"><Grid.RowDefinitions><RowDefinition/><RowDefinition/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><Button Grid.Row="0" Grid.Column="0" MinWidth="50" MinHeight="50" Margin="10">1</Button><Button Grid.Row="0" Grid.Column="1" MinWidth="50" MinHeight="50" Margin="10">2</Button><Button Grid.Row="1" Grid.Column="0" MinWidth="50" MinHeight="50" Margin="10">3</Button><Button Grid.Row="1" Grid.Column="1" MinWidth="50" MinHeight="50" Margin="10">4</Button></Grid></WrapPanel></Grid></Window>
后台代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;namespace WpfApp1
{/// <summary>/// Window1.xaml 的交互逻辑/// </summary>public partial class Window1 : Window{public Window1(){InitializeComponent();}private void CheckBox_Click(object sender, RoutedEventArgs e){CheckBox chb = sender as CheckBox;string index = chb.Name.Substring(3,1);// 在适当的位置调用FindName方法FrameworkElement rootElement = this.FindName("container") as FrameworkElement;FrameworkElement control = LogicalTreeHelper.FindLogicalNode(rootElement, "pnl"+index) as FrameworkElement;if (chb.IsChecked==true){control.Visibility = Visibility.Visible; }else{control.Visibility = Visibility.Collapsed; }}}
}
Visibility 属性是 UIElement 基类的一部分,因此放置于WPF窗口中的任何内容都支持该属性。该属性可使用三个值,它们来自 System.Windows.Visibility 枚举,如下表所示:
值 | 说明 |
---|---|
Visibility | 元素在窗口中正常显示 |
Collapsed | 元素不显示,也不占用任何空间。 |
Hidden | 元素不显示,但仍为其保留空间。 |
本章小结
本章详细介绍了 WPF布局模型,并讨论了如何以堆栈、网格以及其他排列方式放置元素可使用嵌套的布局容器组合创建更复杂的布局,可结合使用 GridSplitter 对象创建可变的分割窗口。本章一直非常关注这一巨大变化的原因—WPF 布局模型在保持、加强以及本地化用户界面方面所具有的优点。
布局内容远不止这些,接下来的几章还将列举更多使用布局容器组织元素分组的示例,还将学习允许在窗口中排列内容的几个附加功能:
- 特殊容器:可以使用 ScrdlIViewer、Tabltem 以及 Expander 控件滚动内容、将内容放到单独的选项卡中以及折叠内容。与布局面板不同,这些容器只能包含单一内容。不过,可以很容易地组合使用这些容器和布局面板,以便准确实现所需的效果。第6 章将尝试使用这些容器。
- Viewbox:需要一种方法来改变图形内容(如图像和矢量图形)的尺寸吗?Viewbox 是另一种特殊容器,可帮助您解决这一问题,而且 Viewbox 控件内置了缩放功能。
- 文本布局:WPF 新增了用于确定大块格式化文本布局的新工具。可使用浮动图形和列表,并且可以使用分页、分列以及更复杂、更智能的換行功能来获得非常完美的结果。
课后作业
无
相关文章:
CH03_布局
第3章:布局 本章目标 理解布局的原则理解布局的过程理解布局的容器掌握各类布局容器的运用 理解 WPF 中的布局 WPF 布局原则 WPF 窗口只能包含单个元素。为在WPF 窗口中放置多个元素并创建更贴近实用的用户男面,需要在窗口上放置一个容器&#x…...
【Oracle】Oracle中的merge into
目录 解释使用场景语法示例案例一案例二 MERGE INTO的优缺点优点:缺点: 注意事项附:Oracle中的MERGE INTO实现的效果,如果改为用MySQL应该怎么实现注意 解释 在Oracle数据库中,MERGE INTO是一种用于对表进行合并&…...
【论文阅读笔记】In Search of an Understandable Consensus Algorithm (Extended Version)
1 介绍 分布式一致性共识算法指的是在分布式系统中,使得所有节点对同一份数据的认知能够达成共识的算法。且算法允许所有节点像一个整体一样工作,即使其中一些节点出现故障也能够继续工作。之前的大部分一致性算法实现都是基于Paxos,但Paxos…...
CentOS 7 网络配置
如想了解请查看 虚拟机安装CentOS7 第一步:查看虚拟机网络编辑器、查看NAT设置 (子网ID,网关IP) 第二步:配置VMnet8 IP与DNS 注意事项:子网掩码与默认网关与 第一步 保持一致 第三步:网络配置…...
2024 React 和 Vue 的生态工具
react Vue...
AI学习指南机器学习篇-t-SNE模型应用与Python实践
AI学习指南机器学习篇-t-SNE模型应用与Python实践 在机器学习领域,数据的可视化是非常重要的,因为它可以帮助我们更好地理解数据的结构和特征。而t-SNE(t-distributed Stochastic Neighbor Embedding)是一种非常强大的降维和可视…...
小试牛刀-Telebot区块链游戏机器人
目录 1.编写目的 2.实现功能 2.1 Wallet功能 2.2 游戏功能 2.3 提出功能 2.4 辅助功能 3.功能实现详解 3.1 wallet功能 3.2 游戏功能 3.3 提出功能 3.4 辅助功能 4.测试视频 Welcome to Code Blocks blog 本篇文章主要介绍了 [Telebot区块链游戏机器人] ❤博主…...
使用github actions构建多平台electron应用
1. 创建electron项目 使用pnpm创建项目 pnpm create quick-start/electron 2. 修改electron-builder.yml文件 修改mac的target mac:target:- target: dmgarch: universal 3. 添加workflow 创建 .github/workflows/main.yml 文件 name: Build/release Electron appon:work…...
java通过pdf-box插件完成对pdf文件中图片/文字的替换
需要引入的Maven依赖: <!-- pdf替换图片 --><dependency><groupId>e-iceblue</groupId><artifactId>spire.pdf.free</artifactId><version>5.1.0</version></dependency> java代码: public AjaxResult replacepd…...
鸿蒙 next 5.0 版本页面跳转传参 接受参数 ,,接受的时候 要先定义接受参数的类型, 代码可以直接CV使用 [教程]
1, 先看效果 2, 先准备好两个页面 index 页面 传递参数 import router from ohos.routerEntry Component struct Index {Statelist: string[] [星期一, 星期二,星期三, 星期四,星期五]StateactiveIndex: number 0build() {Row() {Column({ space: 10 }) {ForEach(this.list,…...
【electron6】浏览器实时播放PCM数据
pcm介绍:PCM(Puls Code Modulation)全称脉码调制录音,PCM录音就是将声音的模拟信号表示成0,1标识的数字信号,未经任何编码和压缩处理,所以可以认为PCM是未经压缩的音频原始格式。PCM格式文件中不包含头部信…...
嵌入式C/C++、FreeRTOS、STM32F407VGT6和TCP:智能家居安防系统的全流程介绍(代码示例)
1. 项目概述 随着物联网技术的快速发展,智能家居安防系统越来越受到人们的重视。本文介绍了一种基于STM32单片机的嵌入式安防中控系统的设计与实现方案。该系统集成了多种传感器,实现了实时监控、报警和远程控制等功能,为用户提供了一个安全、可靠的家居安防解决方案。 1.1 系…...
【Django】django自带后台管理系统样式错乱,uwsgi启动css格式消失的问题
正常情况: ERROR:(css、js文件加载失败) 问题:CSS加载的样式没有了,原因:使用了django自带的admin,在使用 python manage.py runserver启动 的时候,可以加载到admin的文…...
解决npm install(‘proxy‘ config is set properly. See: ‘npm help config‘)失败问题
摘要 重装电脑系统后,使用npm install初始化项目依赖失败了,错误提示:‘proxy’ config is set properly…,具体的错误提示如下图所示: 解决方案 经过报错信息查询解决办法,最终找到了两个比较好的方案&a…...
汽车及零部件研发项目管理系统:一汽东机工选择奥博思 PowerProject 提升研发项目管理效率
在汽车行业中,汽车零部件的研发和生产是一个关键的环节。随着汽车市场的不断扩大和消费者需求的不断增加,汽车零部件项目管理的重要性日益凸显。通过有效的项目管理方法及利用先进的数字项目管理系统,可以大幅提高项目的成功率和顺利度&#…...
Keil开发IDE
Keil开发IDE 简述Keil C51Keil ARMMDK DFP安装 简述 Keil公司是一家业界领先的微控制器(MCU)软件开发工具的独立供应商。Keil公司由两家私人公司联合运营,分别是德国慕尼黑的Keil Elektronik GmbH和美国德克萨斯的Keil Software Inc。Keil公…...
数据结构与算法05堆|建堆|Top-k问题
一、堆 1、堆的介绍 堆(heap)是一种满足特定的条件的完全二叉树,主要可以分为大根堆和小根堆。 大根堆(max heap):任意节点的值大于等于其子节点的值。小根堆(min heap)࿱…...
【精简版】jQuery 中的 Ajax 详解
目录 一、概念 二、jQuery 发送 GET 请求 三、jQuery 发送 POST 请求 四、$.ajax() 方法 1、含义 2、settings 选项 ① type 属性 ② async 属性 ③ headers 属性 ④ contentType 属性 ⑤ processData 属性 ⑥ data 属性 ⑦ timeout 属性 ⑧ beforeSend(jqXHR) 方…...
win10删除鼠标右键选项
鼠标右键菜单时,发现里面的选项特别多,找一下属性,半天找不到。删除一些不常用的选项,让右键菜单变得干净整洁。 1、按下键盘上的“winR”组合按键,调出“运行”对话框,输入“regedit”命令,点击…...
分层评估的艺术:sklearn中的策略与实践
分层评估的艺术:sklearn中的策略与实践 在机器学习中,评估模型性能是一个至关重要的步骤。然而,对于不平衡的数据集,传统的评估方法可能会产生误导性的结果。分层评估(Stratified Evaluation)是一种确保评…...
排序系列 之 快速排序
!!!排序仅针对于数组哦本次排序是按照升序来的哦代码后边有图解哦 介绍 快速排序英文名为Quick Sort 基本思路 快速排序采用的是分治思想,即在一个无序的序列中选取一个任意的基准元素base,利用base将待排序的序列分…...
【银河麒麟服务器操作系统】java进程oom现象分析及处理建议
了解银河麒麟操作系统更多全新产品,请点击访问麒麟软件产品专区:https://product.kylinos.cn 现象描述 某服务器系统升级内核至4.19.90-25.22.v2101版本后仍会触发oom导致java进程被kill。 现象分析 oom现象分析 系统messages日志分析,故…...
Redis的AOF持久化策略(AOF的工作流程、AOF的重写流程,操作演示、注意事项等)
文章目录 缓冲AOF 策略(append only file)AOF 的工作流程AOF 缓冲区策略AOF 的重写机制重写完的AOF文件为什么可以变小?AOF 重写流程 缓冲AOF 策略(append only file) AOF 的核心思路是 “实时备份“,只要我添加了新的数据或者更新了新的数据࿰…...
共享模型之无锁
一、问题提出 1.1 需求描述 有如下的需求,需要保证 account.withdraw() 取款方法的线程安全,代码如下: interface Account {// 获取余额Integer getBalance();// 取款void withdraw(Integer amount);/*** 方法内会启动 1000 个线程…...
下载安装VSCode并添加插件作为仓颉编程入门编辑器
VSCode下载地址:下载 Visual Studio Code - Mac、Linux、Windows 插件下载:GitCode - 全球开发者的开源社区,开源代码托管平台 仓颉社区中下载解压 cangjie.vsix 插件 打开VSCode 按 Ctrl Shift X 弹出下图 按照上图步骤依次点击选中我们下…...
解决:Linux上SVN 1.12版本以上无法直接存储明文密码
问题:今天在Linux机器上安装了SVN,作为客户端使用,首次执行SVN相关操作,输入账号密码信息后,后面再执行SVN相关操作(比如"svn update")还是每次都需要输入密码。 回想以前在首次输入…...
Mongodb多键索引中索引边界的混合
学习mongodb,体会mongodb的每一个使用细节,欢迎阅读威赞的文章。这是威赞发布的第93篇mongodb技术文章,欢迎浏览本专栏威赞发布的其他文章。如果您认为我的文章对您有帮助或者解决您的问题,欢迎在文章下面点个赞,或者关…...
如何利用windows本机调用Linux服务器,以及如何调用jupyter界面远程操控
其实这篇文章没必要存在,教程太多了 参考博客(1 2 3),如侵删 奈何网上的大神总是会漏掉一些凡人遇到的小问题 (1) 建议下载PuTTy for windows,从而建立与远程服务器的SSH连接 需要确认目标服…...
如何定位Milvus性能瓶颈并优化
假设您拥有一台强大的计算机系统或一个应用,用于快速执行各种任务。但是,系统中有一个组件的速度跟不上其他部分,这个性能不佳的组件拉低了系统的整体性能,成为了整个系统的瓶颈。在软件领域中,瓶颈是指整个路径中吞吐…...
阿里云服务器 篇三:提交搜索引擎收录
文章目录 系列文章推荐:为网站注册域名判断网站是否已被搜索引擎收录主动提交搜索引擎收录未查询到收录结果时,根据提示进行提交网站提交网站时一般需要登录账号主动提交网站可缩短爬虫发现网站链接时间,但不保证一定能够收录所提交的网站百度提交地址360搜索提交地址搜狗提…...
建站公司推广/百度快速排名工具
字符串转换为数字异常 当试图将一个String转换为指定的数字类型,而该字符串确不满足数字类型要求的格式时,抛出该异常.如现在讲字符型的数据“123456”转换为数值型数据时,是允许的。 但是如果字符型数据中包含了非数字型的字符,如…...
佛山网站建设哪个好点/宣传推广计划
开发中复杂嵌套时,时常会导致父级事件操作累积在子级身上,相当于子级事件重复执行,即事件累积。类似于定时器的多次叠加 e.g. HTML: 1 <div> 2 <span>123</span> 3 </div> jQueryÿ…...
wordpress编辑器没有16px/网络营销的平台有哪些
一、导读 本文主要内容包括数组转换成List,List转成数组,List转成map的几种方式。 好文章 记得 收藏点赞关注 !!! 二、代码 /*** 练习数组转list,list转数组,list转map** author JiaMing* sin…...
wordpress 结构分析/简述网站内容如何优化
前段时间参加了邀请的《仙风道》内测。一天挑了 25 个问题。下边是一周之后《仙风道》第二次邀请我的时候,我写给他们的信。我在游戏界一年多了,我不想越陷越深…… 《仙风道》确实需要改进。不过按照一般的游戏开发周期,现在这个阶段已经不方…...
如何做网站的逻辑结构图/哪个模板建站好
本文实例为大家分享了python实现烟花小程序的具体代码,供大家参考,具体内容如下FIREWORKS SIMULATION WITH TKINTER *self-containing code *to run: simply type python simple.py in your console *compatible with both Python 2 and Python 3 *Depen…...
教育咨询网站模板/优化网站seo方案
本文实例讲述了Python实现将16进制字符串转化为ascii字符的方法。分享给大家供大家参考,具体如下: 字符串456e633064316e675f31735f66336e,通过Python,按照两个字符,例如45,6e,63形式变成ascii码格式,输出a…...