置顶随笔

[置顶]【WP7-01】Remove Button default Margin / 删除Button默认的Margin

问题

前一段时间写一个布局控件,里面会放到一些Button,Textblock,TextBox等等控件,但是在Button和TextBox控件中发现了问题,发现他们的布局上下左右的“空格”比较大,很是纳闷,以前在Silverlight开发的时候是没有遇见过的。比如:

View Code
        <StackPanel x:Name="ContentPanel">       
            <Button x:Name="btn1" Height="100"/>
            <Button Height="100"/>
            <Button Height="100"/>
        </StackPanel>

显示的效果如下:如果在silverlight上这么写,3个button应该是紧凑在一起的,而WP7却是前后左右都有一些空格。

 

查找原因

用Express Blend 打开此项目,选择其中一个button,右键点击选择Edit Template->Edit a Copy,在弹出框中随便起个名字,点击OK。

然后Blend会生成一个Button的Style:

 

View Code
<Style x:Key="ButtonStyle1" TargetType="Button">
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="BorderBrush" Value="{StaticResource PhoneForegroundBrush}"/>
            <Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/>
            <Setter Property="BorderThickness" Value="{StaticResource PhoneBorderThickness}"/>
            <Setter Property="FontFamily" Value="{StaticResource PhoneFontFamilySemiBold}"/>
            <Setter Property="FontSize" Value="{StaticResource PhoneFontSizeMediumLarge}"/>
            <Setter Property="Padding" Value="10,3,10,5"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Grid Background="Transparent">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal"/>
                                    <VisualState x:Name="MouseOver"/>
                                    <VisualState x:Name="Pressed">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneBackgroundBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneForegroundBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ButtonBackground">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneForegroundBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Disabled">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ButtonBackground">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Transparent"/>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <Border x:Name="ButtonBackground" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="0" Margin="{StaticResource PhoneTouchTargetOverhang}">
                                <ContentControl x:Name="ContentContainer" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
                            </Border>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

原因找到了,原来Button自带的Style有一个Border,并且这个Border里有一个默认的Margin。

大家可以去这个网址查看WP7所有默认的static resource值:http://msdn.microsoft.com/en-us/library/ff769552(v=VS.92).aspx

PhoneTouchTargetOverhang的值是Thickness(12,12,12,12);

也可以在程序中设置断点查看: var r = this.Resources["PhoneTouchTargetOverhang"];

 

解决方法:

1. 最简单的方法是把Style中Border的Margin的值删了,直接写个Margin = "0"  就OK了。

 

2. 不重写Style:通过上面的Style,我们看到Button的controlTemplate是一个Grid,Grid的children( index:0)是Border,所以只要我们找到这个Border,然后把border的Margin置为0就OK了。

这个结构叫做Visual Tree,说白了就是一个Button是有微软的人有N个控件组合在一起而形成的。而最上面xaml中的StackPanel-Button/Button/Button这个叫做Logical Tree。

 

我们要检索Visual Tree,所以会用到VisualTreeHelper这个静态类,对于我们来说,主要用到2个方法:

 

public static DependencyObject GetChild(DependencyObject reference, int childIndex);  // 根据索引,获取child 控件,childIndex就是控件的children[index]

public static int GetChildrenCount(DependencyObject reference);                                 // 获取reference控件的children数量

 

因为我们已经知道了Button的ControlTemplate结构,可以在Button的Loaded代码里直接这么写代码,如下,当然你也可以写一个通用的递归帮助方法来通过Name查找Border控件。

 

View Code
private void btn1_Loaded(object sender, RoutedEventArgs e)
        {
            Button btn = sender as Button;
            Grid grid = VisualTreeHelper.GetChild(btn, 0) as Grid;
            Border border = VisualTreeHelper.GetChild(grid, 0) as Border;
            border.Margin = new Thickness(0);
        }

 

解决完的截图:

可以看到,现在3个Button紧密的凑合在一起了。当然,真正的使用还需要手动给分配Margin或者在定义Grid行列的时候自动带出来空隙。

 

PS:

1. this.Resources是一个字典ResourceDictionary类型,我当初试着操作这个字典,比如update或者先删除PhoneTouchTargetOverhang key再添加一个key,最后都不可以。看来微软是不让改系统自带的资源,如果有其他方法改动的话,请留言。

2. 对于TextBox思路也是一样的.

 

Demo 工程下载  (VS2010 7.1)

 

后话:大家都说违背了微软设计的初衷,我后来又想了想,我估计大家没有仔细看完,比如我上面那段话,大家肯定以为我是直接把3个紧挨着的Button拿来直接使用,其实不是这样的,我是要在一个Grid中统一布局,肯定会留出一些间隔/空隙。这样应该不会惹来那么多争议了把? 

posted @ 2011-10-24 23:21 潇潇兮 阅读(931) 评论(8) 编辑

[置顶]Silverlight Office Room People/Seat/Device Viewer

 
此程序展现一层办公室里人员,座位以及硬件设备情况。
心得:Expression Blend 真是个好东西,应该深入学习一下! 

posted @ 2011-07-29 22:25 潇潇兮 阅读(144) 评论(0) 编辑

[置顶]Silverlight Curve Animation / 曲线动画

posted @ 2011-07-22 15:42 潇潇兮 阅读(241) 评论(0) 编辑

[置顶]Silverlight Stick Game

 
游戏规则:每次去掉(点击)最上面的棍子。
Bug:从肉眼来看,有时会有〉1的棍子都在最上面,但是只能点击特定的才可继续。

posted @ 2011-07-20 10:43 潇潇兮 阅读(200) 评论(3) 编辑

[置顶]Silverlight Ball Movement Game Draft

 
游戏说明:
1. 把右边的轨道正确的放到左边的位置,使小球从起点滚到终点。
(右边前3个选择轨道,点击某一个轨道,然后再点击到左边的空地处即可安装轨道。最后一个是炸弹道具,可以清除轨道)
2. 每关必须吃掉红色的*才可以过关。
3. 失败后,点击Restart重新开启游戏。
4. 安装完轨道之后,点击Fast按钮可以让小球和读秒时间加快。
4. 游戏不太美观,正在努力修改中。。。

示例图片:
 

posted @ 2011-01-09 16:24 潇潇兮 阅读(310) 评论(2) 编辑

2011年10月24日

【WP7-01】Remove Button default Margin / 删除Button默认的Margin

摘要: 问题前一段时间写一个布局控件,里面会放到一些Button,Textblock,TextBox等等控件,但是在Button和TextBox控件中发现了问题,发现他们的布局上下左右的“空格”比较大,很是纳闷,以前在Silverlight开发的时候是没有遇见过的。比如:View Code <StackPanelx:Name="ContentPanel"> <Buttonx:Name="btn1"Height="100"/><ButtonHeight="100"/><ButtonH阅读全文

posted @ 2011-10-24 23:21 潇潇兮 阅读(931) 评论(8) 编辑

2011年7月29日

Silverlight Office Room People/Seat/Device Viewer

摘要: 此程序展现一层办公室里人员,座位以及硬件设备情况。心得:Expression Blend 真是个好东西,应该深入学习一下!阅读全文

posted @ 2011-07-29 22:25 潇潇兮 阅读(144) 评论(0) 编辑

2011年7月22日

Silverlight Curve Animation / 曲线动画

posted @ 2011-07-22 15:42 潇潇兮 阅读(241) 评论(0) 编辑

2011年7月20日

Silverlight Stick Game

摘要: 游戏规则:每次去掉(点击)最上面的棍子。Bug:从肉眼来看,有时会有〉1的棍子都在最上面,但是只能点击特定的才可继续。阅读全文

posted @ 2011-07-20 10:43 潇潇兮 阅读(200) 评论(3) 编辑

2011年4月29日

WPF 设置windows窗体在最前端 top window / Foreground Window

摘要: 需要实现的功能是当鼠标滑过WPF窗体的textbox时,获取textbox的输入焦点。步骤:1.需要把此WPF的Topmost属性设置成true。2.引用 win32 API 函数:View Code [DllImport("user32.dll")]privatestaticexternboolSetForegroundWindow(IntPtrhWnd);[DllImport("user32.dll")]privatestaticexternIntPtrSetFocus(IntPtrhWnd);2.添加Textbox的MouseEnter事件View阅读全文

posted @ 2011-04-29 16:56 潇潇兮 阅读(373) 评论(1) 编辑

2011年3月17日

Jimmy's Mini Dict 英语字典 | C# WPF ICIBA

摘要: 英语翻译字典小程序,省着打开网页查了,适合懒人。需要联网的,感兴趣的朋友可以下载用用 下载地址: 点我下载该程序需要.Net framework 4:http://www.microsoft.com/downloads/en/details.aspx?FamilyID=9cfb2d51-5ff4-4491-b0e5-b386f32c0992&displaylang=en此程序连接的是 http://www.iciba.com/阅读全文

posted @ 2011-03-17 23:12 潇潇兮 阅读(256) 评论(2) 编辑

2011年3月11日

【原创】Perl语言入门学习笔记

摘要: $指一个 ,@指一堆,%指hash---------------------------------------------------x 字符串重复操作符.Eg: "fred" x 3 = "fredfredfred"------------------------------------------------------数组:$#数组名 最后一个元素的索引值$数据名[-1] 最后一个元素pop和push在最后段操作,shift和unshift在最左端操作reverse 反转列表元素sort 对列表的值排序 $_ 默认变量.Eg: foreach循环阅读全文

posted @ 2011-03-11 10:00 潇潇兮 阅读(111) 评论(0) 编辑

2011年2月12日

【原创】Perl 正则表达式基础整理

摘要: . 任何单字符的通配符(\n除外)* 匹配前面的内容零次或多次。+ 匹配前面的内容一次或多次。?匹配前面的内容零次或一次。 非贪婪符号。() 模式分组\1 反向(重复)引用圆括号中匹配的文字。| 或(择一匹配)[] 字符集。Eg: [a-zA-Z], [abcxyz]^ 脱字符 表示这些字符除外。只在字符集中使用。\d 数字\w 单词字符 (数字,字母和下划线) [a-zA-Z0-9_]\s 空白字符 (相当于[\f\t\n\r])\D 非数字\W 非单词\S 非空白{} 字符出现次数。Eg: /a{5,15}/ 出现5到15次的字母a。/(fred){3,}/ 重复次数3次以上+? 非贪婪的阅读全文

posted @ 2011-02-12 14:46 潇潇兮 阅读(84) 评论(0) 编辑

2011年1月9日

Silverlight Ball Movement Game Draft

摘要: 游戏说明: 1. 把右边的轨道正确的放到左边的位置,使小球从起点滚到终点。(右边前3个选择轨道,点击某一个轨道,然后再点击到左边的空地处即可安装轨道。最后一个是炸弹道具,可以清除轨道)2. 每关必须吃掉红色的*才可以过关。 3. 失败后,点击Restart重新开启游戏。4. 安装完轨道之后,点击Fast按钮可以让小球和读秒时间加快。4. 游戏不太美观,正在努力修改中。。。示例图片:阅读全文

posted @ 2011-01-09 16:24 潇潇兮 阅读(310) 评论(2) 编辑