布局实际上是一个Slot模型,其中每个父对象分配给子对象一个Slot,子对象可以自由占用Slot中的空间,通过Margin\VerticalAlignment\HorizontalAlignment控制

实例

<Border Background="LightBlue" BorderBrush="Black" BorderThickness="" CornerRadius="" Padding="">
<StackPanel Name="SP1" Background="White">
<TextBlock FontSize="" HorizontalAlignment="Center" Margin="0,0,0,15" Text="StackPanel1"></TextBlock>
<Border BorderThickness="" BorderBrush="Black">
<Button Margin="5,10,15,20">Normal</Button>
</Border>
<Border BorderThickness="" BorderBrush="Black">
<Button Margin="5,10,15,20" HorizontalAlignment="Left">
<Button.LayoutTransform>
<RotateTransform Angle="" />
</Button.LayoutTransform>
Left</Button>
</Border>
<Border BorderThickness="" BorderBrush="Black">
<Button Margin="5,10,15,20" HorizontalAlignment="Right">
<Button.LayoutTransform>
<RotateTransform Angle="" />
</Button.LayoutTransform>
Right</Button>
</Border>
<Border BorderThickness="" BorderBrush="Black">
<Button Margin="5,10,15,20" HorizontalAlignment="Center">
<Button.LayoutTransform>
<RotateTransform Angle="" />
</Button.LayoutTransform>
Center</Button>
</Border>
<Border BorderThickness="" BorderBrush="Black">
<Button Margin="5,10,15,20" >
<Button.LayoutTransform>
<RotateTransform Angle="" />
</Button.LayoutTransform>
LayoutTransform
</Button>
</Border>
<Border BorderThickness="" BorderBrush="Black">
<Button Margin="5,10,15,20" >
<Button.RenderTransform>
<RotateTransform Angle="" />
</Button.RenderTransform>
RenderTransform
</Button>
</Border>
</StackPanel>
</Border>

注意LayoutTransform和RenderTransform的区别

自定义布局

确定空间最佳尺寸经历两个阶段,1.测量,父元素询问子元素期望的尺寸,来确定自身尺寸 2.布置,父元素告知子元素的位置

具体实现为以下两个重载函数

protected override Size ArrangeOverride(Size arrangeBounds);
protected override Size MeasureOverride(Size constraint);

自定义CustomPanel

public class CustomPanel : Panel
{
public CustomPanel()
: base()
{
} protected override Size MeasureOverride(Size availableSize)
{
double maxChildWidth = 0.0;
double maxChildHeight = 0.0;
foreach (UIElement child in InternalChildren)
{
child.Measure(availableSize);
maxChildWidth = Math.Max(child.DesiredSize.Width, maxChildWidth);
maxChildHeight = Math.Max(child.DesiredSize.Height, maxChildHeight);
} double idealCircumference = maxChildWidth * InternalChildren.Count;
double idealRadius = idealCircumference / (Math.PI * ) + maxChildHeight; Size desired = new Size(idealRadius * , idealRadius * ); if (!double.IsInfinity(availableSize.Width))
{
if (availableSize.Width < desired.Width)
desired.Width = availableSize.Width;
}
if (!double.IsInfinity(availableSize.Height))
{
if (availableSize.Height < desired.Height)
desired.Height = availableSize.Height;
} return desired;
} protected override Size ArrangeOverride(Size finalSize)
{
Rect layoutRect;
if (finalSize.Width > finalSize.Height)
{
layoutRect = new Rect((finalSize.Width - finalSize.Height) / , , finalSize.Height, finalSize.Height);
}
else
{
layoutRect = new Rect((finalSize.Height - finalSize.Width) / , , finalSize.Width, finalSize.Width);
} double angleInc = / InternalChildren.Count;
double angle = ;
foreach (UIElement child in InternalChildren)
{
Point childLocation = new Point(layoutRect.Left + (layoutRect.Width - child.DesiredSize.Width) / , layoutRect.Top);
child.RenderTransform = new RotateTransform(angle, child.DesiredSize.Width / , finalSize.Height / - layoutRect.Top);
angle += angleInc;
child.Arrange(new Rect(childLocation, child.DesiredSize));
} return finalSize;
}
}
<Page x:Class="Alex_WPFAPPDemo09.DemoPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Alex_WPFAPPDemo09"
mc:Ignorable="d"
d:DesignHeight="" d:DesignWidth=""
Title="DemoPage"> <Grid Margin="">
<local:CustomPanel>
<Button Content="" MinWidth="" />
<Button Content="" MinWidth="" />
<Button Content="" MinWidth="" />
<Button Content="" MinWidth="" />
<Button Content="" MinWidth="" />
<Button Content="" MinWidth="" />
<Button Content="" MinWidth="" />
</local:CustomPanel>
</Grid>
</Page>

To be continue...

WPF学习之路(十一)布局(续)的更多相关文章

  1. WPF学习之路初识

    WPF学习之路初识   WPF 介绍 .NET Framework 4 .NET Framework 3.5 .NET Framework 3.0 Windows Presentation Found ...

  2. WPF学习(一)--布局控件简介

    WPF的4种基本布局介绍 1.Grid的布局 这个就没啥特别好说的,其实,基本上复杂的布局,都需要用到Grid. 主要就是对行和列进行进行设置和定义. 1.行表格 列表格: 包含行和列的表格 2.St ...

  3. WPF学习(3)布局

    今天我们来说说WPF的布局.我们知道WinForm的布局主要是采用基于坐标的方式,当窗口内容发生变化时,里面的控件不会随之动态调整,这就造成了一个很不好的用户体验.而WPF为了避免这个缺点,采用了基于 ...

  4. 【WPF学习】第二十一章 特殊容器

    内容控件不仅包括基本控件,如标签.按钮以及工具提示:它们还包含特殊容器,这些容器可用于构造用户界面中比较大的部分区域. 首先介绍ScrollViewer控件,该控件直接继承自ContentContro ...

  5. WPF学习之路(十一)布局

    布局 Canvas 基本面板,传统布局方式,支持与设备无关的坐标定位元素 <Border BorderThickness="> <Canvas> <Button ...

  6. WPF学习之路(二) XAML(续)

    属性 简单属性 前面用到的Width/Height都是简单属性,其赋值一定要放到双引号里 XAML解析器会根据属性的类型执行隐式转换 与C#的区别 SolidBrush.Color = Colors. ...

  7. WPF学习之路(九)导航和页面(续)

    生命周期 如果Page1成功导航到Page2,首先会触发NavigationService的Navigating事件,标识导航开始.随后创建Page2对象,并且触发NavigationProgress ...

  8. WPF学习之路(七)应用程序和窗口(续)

    窗口的生命周期 WPF中一个Window类代表一个窗口 一个的窗口的生命周期也有好几个阶段: 1.构造器被调用 2.Window.Initialized事件被触发 3.Window.Activated ...

  9. WPF学习之路(五) 实例:写字板(续)

    WordPad 2.0 上一期实现了一虽然建议但是功能比较全面的Wordpad程序,但是程序代码略显繁琐,这一期更新改进版. MainWindows.xaml 添加 <Window.Comman ...

随机推荐

  1. java开源时间/日期库Joda-Time

    任何企业应用程序都需要处理时间问题.应用程序需要知道当前的时间点和下一个时间点,有时它们还必须计算这两个时间点之间的路径.使用 JDK 完成这项任务将非常痛苦和繁琐.现在来看看 Joda Time,一 ...

  2. 【iOS】配置和使用静态库

    上一篇 我们演示了了如何创建自己的静态库,最终生成多个.a文件,根据需要引用工程就可以直接使用静态库了,但是有个很麻烦的问题,模拟器用的库和真机的不是同一个,当我们切换的时候需要更换静态库,有两种方式 ...

  3. 三星S4,呼转的来电,在来电界面上不显示的解决方案

    因为工作关系,我有2个号码是呼叫转移到我现在的手机上的,如果有呼叫转移的来电的话,在通话界面里面没有提示该来电是呼叫转移来的.之前我用的诺基亚的,可以看到呼叫转移的来电,在号码的左边有个拐弯的箭头,提 ...

  4. js Date 时间格式化的扩展

    js Date 时间格式化的扩展: Date.prototype.format = function (fmt) { var o = { , //月 "d+": this.getD ...

  5. LeetCode121:Best Time to Buy and Sell Stock

    题目: Say you have an array for which the ith element is the price of a given stock on day i. If you w ...

  6. XMPP客户端开发(1)--连接和登录

    Smack可用于XMPP客户端的开发,下载Smack,将相关jar文件导入后,即可以开始XMPP客户端的开发. 以下代码实现了客户端连接Tigase服务器,并根据用户名和密码登录. package X ...

  7. [函数] Firemonkey iOS 指定目录不要备份到 iCloud

    uses iOSapi.Foundation, Macapi.Helpers; // 不要备份到 iCloud by Aone function addSkipBackupAttributeToIte ...

  8. java的spilt(“,”)方法bug处理

    java split方法以逗号分隔如字符串",,,,,," 这样会得到一个空的数组 String str ={1,2,3,,,,, } String[] str1 =spilt(& ...

  9. soap缓存问题

    问题描述: ws提供方在原有基础上增加了一个方法,通过php的soap扩展硬是获取不到该方法,提示,该方法不存在. 问题跟节: soap缓存问题,导致无法获取最新的ws文件信息 解决办法: 1.直接在 ...

  10. Asynchronous Jobs

    Because Play is a web application framework, most of the application logic is done by controllers re ...