3.2 自定义布局规则

上一节介绍了Windows Phone的系统布局面板和布局系统的相关原理,那么系统的布局面板并不一定会满足所有的你想要实现的布局规律,如果有一些特殊的布局规律,系统的布局面板是不支持,这时候就需要去自定义实现一个布局面板,在自定义的布局面板里面封装布局规律的逻辑。那么我们这一节从一个实际的需求出发,来实现一个自定义规律的布局面板。我们这一小节要实现的布局规律是把布局面板里面的子元素,按照圆形的排列规则进行排列,下面我们来看下这个例子的详细实现过程。

3.2.1 创建布局类

在Windows Phone要实现类似Grid、StackPanel的自定义布局规则的面板,首先要做的事情是要创建一个自定义的布局类。所有的布局面板都需要从Panel类派生,自定义实现其测量和排列的过程。Panel类中的Children属性表示是布局面板里面的子对象,测量和排列的过程中需要根据Children属性来获取面板中所有的子对象,然后再根据相关的规律对这些子对象进行测量和排列。

如果我们的布局类需要外面传递进来一些特殊的参数,那么就需要我们在布局类里面去实现相关的属性。当然像Heigh、Width等这些Panel类原本就支持的属性我们就无需再去定义,如我们在这个例子里面要实现的圆形布局,这时候是需要一个圆形的半径大小的,这个半径的大小就可以作为一个属性让外面把数值传递进来,然后布局类再根据这个半径的大小来进行处理对子对象的测量和排列。需要注意的是,自定义的半径属性发生改变的时候,需要调用InvalidateArrange方法重新触发布局的排列过程,否则修改半径后将不会起到任何作用。

代码清单3-2自定义布局规则(源代码:第3章\Examples_3_2)

下面我们来看一下,自定义的CirclePanel类:

    public class CirclePanel : Panel
{
//自定义的半径变量
private double _radius = ;
public CirclePanel()
{
}
//注册半径依赖属性
//"Radius" 表示半径属性的名称
// typeof(double) 表示半径属性的类型
// typeof(CirclePanel) 表示半径属性的归属者类型
// new PropertyMetadata(0.0, OnRadiusPropertyChanged)) 表示半径属性的元数据实例,0.0是默认值,OnRadiusPropertyChanged是属性改变的事件
public static readonly DependencyProperty RadiusProperty = DependencyProperty.RegisterAttached
("Radius",
typeof(double),
typeof(CirclePanel),
new PropertyMetadata(0.0, OnRadiusPropertyChanged));
//定义半径属性
public double Radius
{
get { return (double)GetValue(RadiusProperty); }
set { SetValue(RadiusProperty, value); }
}
//实现半径属性改变事件
private static void OnRadiusPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
//获取触发属性改变的CirclePanel对象
CirclePanel target = (CirclePanel)obj;
//获取传递进来的最新的值,并赋值给半径变量
target._radius = (double)e.NewValue;
//使排列状态失效,进行重新排列
target.InvalidateArrange();
}
//重载基类的MeasureOverride方法
protected override Size MeasureOverride(Size availableSize)
{
//处理测量子对象的逻辑
return availableSize;
}
//重载基类的ArrangeOverride方法
protected override Size ArrangeOverride(Size finalSize)
{
//处理排列子对象的逻辑
return finalSize;
}
}

3.2.2 实现测量过程

测量的过程是在重载的MeasureOverride方法上实现,在MeasureOverride方法上需要做的第一件事情就是要把所有的子对象都遍历一次,调用其Measure方法来测量子对象的大小。然后在测量的过程中可以获取到子对象测量出来的宽度高度,我们可以根据这些信息来给自定义的面板分配其大小。

    protected override Size MeasureOverride(Size availableSize)
{
//最大的宽度的变量
double maxElementWidth = ;
//遍历所有的子对象,并调用子对象的Measure方法进行测量,取出最大的宽度的子对象
foreach (UIElement child in Children)
{
//测量子对象
child.Measure(availableSize);
maxElementWidth = Math.Max(child.DesiredSize.Width, maxElementWidth);
}
//两个半径的大小和最大的宽度的两倍最为面板的宽度
double panelWidth = * this.Radius + * maxElementWidth;
//取面板的所分配的高度宽度和计算出来的宽度的最小值最为面板的实际大小
double width = Math.Min(panelWidth, availableSize.Width);
double heigh = Math.Min(panelWidth, availableSize.Height);
return new Size(width, heigh);
}

3.2.3 实现排列过程

排列的过程是在重载的ArrangeOverride方法上实现,在ArrangeOverride方法上通过相关的规则把子对象一一地进行排列。我们在例子里面要实现的是把子对象按照一个固定的圆形进行排列,所以在ArrangeOverride方法上需要计算每个子对象所占的角度大小,通过角度计算子对象在面板中的坐标,然后按照一定的角度对子对象进行旋转来适应圆形的布局。排列原理图如图3.7所示,实现代码如下。

    protected override Size ArrangeOverride(Size finalSize)
{
//当前的角度,从0开始排列
double degree = ;
//计算每个子对象所占用的角度大小
double degreeStep = (double) / this.Children.Count;
//计算
double mX = this.DesiredSize.Width / ;
double mY = this.DesiredSize.Height / ;
//遍历所有的子对象进行排列
foreach (UIElement child in Children)
{
//把角度转换为弧度单位
double angle = Math.PI * degree / 180.0;
//根据弧度计算出圆弧上的x,y的坐标值
double x = Math.Cos(angle) * this._radius;
double y = Math.Sin(angle) * this._radius;
//使用变换效果让控件旋转角度degree
RotateTransform rotateTransform = new RotateTransform();
rotateTransform.Angle = degree;
rotateTransform.CenterX = ;
rotateTransform.CenterY = ;
child.RenderTransform = rotateTransform;
//排列子对象
child.Arrange(new Rect(mX + x, mY + y, child.DesiredSize.Width, child.DesiredSize.Height));
//角度递增
degree += degreeStep;
}
return finalSize;
}

3.2.4 应用布局规则

在上面我们已经把自定义的圆形布局控件实现了,现在要在XAML页面上应用该布局面板来进行布局。在这个例子里面,我们还通过一个Slider控件来动态改变布局面板的半径大小,来观察布局的变化。

首先我们在XAML页面上引入布局面板所在的空间,如下所示:

xmlns:local="clr-namespace:CustomPanelDemo"

然后在XAML页面上运用自定义的圆形布局控件,并且通过Slider控件的ValueChanged来动态给圆形布局控件的半径赋值。代码如下:

MainPage.xaml文件主要代码
------------------------------------------------------------------------------------------------------------------
<Grid x:Name="ContentPanel" Grid.Row="" Margin="12,0,12,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Slider Grid.Row="" Value="" ValueChanged="Slider_ValueChanged_1"></Slider>
<local:CirclePanel x:Name="circlePanel" Radius="" Grid.Row="" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock>Start here</TextBlock>
<TextBlock>TextBlock </TextBlock>
<TextBlock>TextBlock </TextBlock>
<TextBlock>TextBlock </TextBlock>
<TextBlock>TextBlock </TextBlock>
<TextBlock>TextBlock </TextBlock>
<TextBlock>TextBlock </TextBlock>
<TextBlock>TextBlock </TextBlock>
</local:CirclePanel>
</Grid>
MainPage.xaml.cs文件主要代码
------------------------------------------------------------------------------------------------------------------
private void Slider_ValueChanged_1(object sender, RangeBaseValueChangedEventArgs e)
{
if (circlePanel != null)
{
circlePanel.Radius = e.NewValue * ;
}
}

本文来源于《深入理解Windows Phone 8.1 UI控件编程》

源代码下载:http://vdisk.weibo.com/s/zt_pyrfNHoezI

欢迎关注我的微博@WP林政

WP8.1技术交流群:372552293

[WP8.1UI控件编程]Windows Phone自定义布局规则的更多相关文章

  1. [WP8.1UI控件编程]Windows Phone VirtualizingStackPanel、ItemsStackPanel和ItemsWrapGrid虚拟化排列布局控件

    11.2.2 VirtualizingStackPanel.ItemsStackPanel和ItemsWrapGrid虚拟化排列布局控件 VirtualizingStackPanel.ItemsSta ...

  2. [WP8.1UI控件编程]Windows Phone动画方案的选择

    8.1 动画方案的选择 Windows Phone的动画实现方式有线性插值动画(3种类型).关键祯动画(4种类型)和基于帧动画,甚至还有定时器动画,然后动画所改变的UI元素属性可以是普通的UI元素属性 ...

  3. [WP8.1UI控件编程]Windows Phone理解和运用ItemTemplate、ContentTemplate和DataTemplate

    2.2.5 ItemTemplate.ContentTemplate和DataTemplate 在理解ItemTemplate.ContentTemplate和DataTemplate的关系的之前,我 ...

  4. [WP8.1UI控件编程]Windows Phone XAML页面的编译

    1.1.2 XAML页面的编译 Windows Phone的应用程序项目会通过Visual Studio完成XAML页面的编译,在程序运行时会通过直接链接操作加载和解析XAML,将XAML和过程式代码 ...

  5. [WP8.1UI控件编程]Windows Phone大数据量网络图片列表的异步加载和内存优化

    11.2.4 大数据量网络图片列表的异步加载和内存优化 虚拟化技术可以让Windows Phone上的大数据量列表不必担心会一次性加载所有的数据,保证了UI的流程性.对于虚拟化的技术,我们不仅仅只是依 ...

  6. [WP8.1UI控件编程]SemanticZoom控件实现分组列表

    11.1.5 SemanticZoom实现分组列表 SemanticZoom控件可以让用户实现一种更加高级的列表,这种列表可以对列表的项目进行分组,同时这个SemanticZoom控件会提供两个具有相 ...

  7. 《深入理解Windows Phone 8.1 UI控件编程》基于最新的Runtime框架

    <深入理解Windows Phone 8.1 UI控件编程>本书基于最新的Windows Phone 8.1 Runtime SDK编写,全面深入地论述了最酷的UI编程技术:实现复杂炫酷的 ...

  8. MFC控件编程之 按钮编辑框.静态文本的使用,以及访问控件的七种方法.

    MFC控件编程之 按钮编辑框.静态文本的使用以及访问控件的七种方法. 一丶按钮.静态文本的通用属性. 他们都有一个属性.就是可以输入标题内容.以及可以自定义控件ID. 创建一个MFC Dlg对话框. ...

  9. MFC控件编程之鼠标跟键盘消息

    MFC控件编程之鼠标跟键盘消息 在MFC中鼠标消息.键盘消息我们很常用.所以说一下. 鼠标消息分为客户区消息.跟非客户区消息. 一丶客户区消息 我们可以处理消息.来进行我们相应的函数即可. MFC添加 ...

随机推荐

  1. SVM 最大间隔目标优化函数(NG课件2)

        目标是优化几何边距, 通过函数边距来表示需要限制||w|| = 1     还是优化几何边距,St去掉||w||=1限制转为普通函数边距     更进一步的,可以固定函数边距为1,调节||w| ...

  2. 傻瓜式十分钟免费开启 HTTPS,是时候为你的站点加上小绿锁了

    http://gold.xitu.io/entry/57df65690bd1d00057f9455b?from=singlemessage&isappinstalled=0 原文链接:http ...

  3. 【JAVA多线程问题之死锁】

    一.死锁是什么? 举个例子:两个人一起吃饭,每个人都拿了一只筷子,双方都在等待对方将筷子让给自己,结果两个人都吃不了饭.这种情况和计算机中的死锁情况很相似. 假设有两个线程,互相等待对方释放占有的锁, ...

  4. 【PHP绘图技术&&验证码绘制】

    PHP绘图是比较简单的事情,基本绘图如直线.圆.矩形.弧线.填充矩形.填充扇形.非中文字的打印.中文文字的打印在在下面的代码中会纤细讲解. 需要支持中文的字体,可以到windows自带的字体库中找,并 ...

  5. [LeetCode] Validate Binary Search Tree (两种解法)

    Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is defined as ...

  6. Win7下的内置FTP组件的设置详解

    在局域网中共享文件,FTP是比较方便的方案之一.Win7内部集成了FTP,只是设置起来颇费一番功夫.着文以记之. 一.安装FTP组件 由于Win7默认没有安装FTP组件.故FTP的设置第一步就是安装F ...

  7. Oracle里SID、SERVICE_NAME

    本文仅用作备忘,无实际指导意义,逻辑略混乱. 1.命令show parameter name; SQL> show parameter name; NAME TYPE VALUE ------- ...

  8. POJ 1061 同余方程

    两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面.它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止.可是 它们出发之前忘记了一件很重要的事情,既没有问清楚对方的 ...

  9. [Tools] maven-eclipse安装及配置

    [背景] 买了个surface,带到公司当做开发机器来用,各种环境都需要重新安装,写个笔记记录下maven安装步骤,虽然很简单,但是我这脑子,容易忘记,写下来以备用 [开工] 安装Maven 访问 M ...

  10. Iphone [Tab Bar实现多view切换,Picker,DataPicter实现

    用Tab Bar Controller处理IPhone多个view切换, 而且还附有创建空项目,picker和DataPicker的实现! 具体步骤: 1.创建一个空项目,选择User Interfa ...