各位好,终于讲到自定义Panel了。当系统自带的几个Panel比如Gird,StackPanel,RelativePanel不能满足我们的特定要求时(其实不常见啦),自定义Panel就显得非常必要,而且因为是针对性的处理,效果也会非常好。更何况自定义Panel其实并不复杂,今天俺们就来学习一下。

  记得上一篇自定义CommandBar在增加占位控件AppBarEmpty时,采用的是通过Page的SizeChanged事件中计算页面Width,减去CommandBar中其他控件Width后再赋值Width给AppBarEmpty的方法。就可行性而言是绝对没问题的,代码复杂度也很低,不失为一个好方法。但是复用性不太好,需要在每个Page都写上一小段代码。而我们的初衷是希望AppBarEmpty能够自动撑开,计算自身所需的Width。

  遇到的困难来自StackPanel这个控件,StackPanel在计算自身所需空间时,会非常吝啬按children元素所需的最小尺寸来申请。就好比申请经费时按最下限申请,这种精神ZF部门应该学习,而公司组织TeamBuilding就应该排斥……)。说到这里,本篇的主题有了,就是通过自定义一个StackPanelEx来实现让AppBarEmpty自动撑开的效果。

  前面说了,自定义Panel其实并不复杂。只有两个方法需要override:

        //
// Summary:(根据子元素测量控件本身需要的空间)
// Provides the behavior for the Measure pass of the layout cycle. Classes can override
// this method to define their own Measure pass behavior.
//
// Parameters:
// availableSize:(控件本身的可用空间。如指定无穷大值,表示控件的大小将调整为内容的可用大小)
// The available size that this object can give to child objects. Infinity can be
// specified as a value to indicate that the object will size to whatever content
// is available.
//
// Returns:(控件根据子元素大小计算得出的所需大小)
// The size that this object determines it needs during layout, based on its calculations
// of the allocated sizes for child objects or based on other considerations such
// as a fixed container size.
protected virtual Size MeasureOverride(Size availableSize);
//
// Summary:(根据上面测量的结果,来对子元素进行布局)
// Provides the behavior for the Arrange pass of layout. Classes can override this
// method to define their own Arrange pass behavior.
//
// Parameters:
// finalSize:(控件用来排列自身及其子元素的最终确定的空间)
// The final area within the parent that this object should use to arrange itself
// and its children.
//
// Returns:(使用的实际大小)
// The actual size that is used after the element is arranged in layout.
protected virtual Size ArrangeOverride(Size finalSize);

  听上去是不是挺绕的?我们来看StackPanelEx的实际代码:

    public class StackPanelEx : Panel
{
protected override Size MeasureOverride(Size availableSize)
{
    double height = ;
foreach (var child in Children)
{
// Tell the child control to determine the size needed
child.Measure(availableSize);
height = child.DesiredSize.Height > height ? child.DesiredSize.Height : height;
} return new Size(availableSize.Width,height);
} protected override Size ArrangeOverride(Size finalSize)
{
int count = Children.Count(_ => _ is AppBarEmpty2);
double totalLength = Children.Where(_ => _ is AppBarEmpty2 == false).Sum(_ => (_ as FrameworkElement).Width);
var emptyWidth = (finalSize.Width - totalLength) / count; double x = ;
foreach (var child in Children)
{
if (child is AppBarEmpty2)
{
child.Arrange(new Rect(x, , emptyWidth, ));
x += emptyWidth;
}
else
{
child.Arrange(new Rect(x, , child.DesiredSize.Width, child.DesiredSize.Height));
x += child.DesiredSize.Width;
}
}
return finalSize;
}
}

  简单解释一下,首先在MeasureOverride方法里,告诉每个子元素(这里是AppBarButton和AppBarEmpty2)去算自己需要多少空间,一会要分地了。然后直接告诉上头,Width我全要了,Height按我们村里最高的人给就行了。

  紧接着到了ArrangeOverride方法,上级领导比较大方,告诉该控件Width全给你,还有你Height要的太少,拖了上级Panel的后腿,多给一些Height免得挤到同级的其他控件……

  然后村长及开始分地了。AppBarButton就按他自己申请的给,AppBarEmpty2感觉是村长亲戚,剩下的Width全给他们家承包了……

  最后向上头汇报一下分地的情况,这事就算完了。

  AppBarEmpty2还是没变,和上次一样。

    public class AppBarEmpty2 : FrameworkElement, ICommandBarElement
{
public bool IsCompact { get; set; }
}

  既然新的StackPanelEx写好了,就该替换CommandBar原有的StackPanel了,找到CommandBar模板中关于PrimaryItemsControl的部分

                                <Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<ContentControl x:Name="ContentControl" ContentTemplate="{TemplateBinding ContentTemplate}" ContentTransitions="{TemplateBinding ContentTransitions}" Content="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" IsTabStop="False" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
<ItemsControl x:Name="PrimaryItemsControl" Grid.Column="0"
HorizontalAlignment="Stretch" IsTabStop="False" MinHeight="{ThemeResource AppBarThemeMinHeight}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<!--<StackPanel Orientation="Horizontal"/>-->
<local:StackPanelEx ></local:StackPanelEx>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>

  将ItemsPanelTemplate中的StackPanel替换成StackPanelEx,同时将ItemsControl的HorizontalAlignment="Right"改成HorizontalAlignment="Stretch",大功告成,再来看一下Page中的XAML部分:

       <CommandBar x:Name="commandBar" Grid.Row="3" Style="{StaticResource CommandBarStyle2}" >
<AppBarButton x:Name="appbarButton" Icon="Accept" Label="fdsfdsf" ></AppBarButton>
<local:AppBarEmpty2 ></local:AppBarEmpty2>
<AppBarButton Icon="Accept" Label="fdsfdsf"></AppBarButton>
<local:AppBarEmpty2 ></local:AppBarEmpty2>
<AppBarButton Icon="Accept" Label="fdsfdsf" ></AppBarButton>
</CommandBar>

  是不是非常的清爽,再也不用去写什么SizeChanged事件了。实际效果如下图:

最新文章

  1. Vim 快速上手
  2. NoSQL学习——MongoDB
  3. 【linux】学习5
  4. BizTalk开发系列(六) BizTalk开发简述
  5. [daily][device] linux添加打印机
  6. android技巧(一):如何方便知晓当前Activity?如何管理应用中的Activity?如何最佳的启动一个Activity?
  7. Sql触发器模板
  8. Centos7+Apache2.4+php5.6+mysql5.5搭建Lamp环境——为了wordPress
  9. c - 每位数字尾部加空格
  10. 对js运算符“||”和“&amp;&amp;”的总结
  11. Ubuntu下使用nginx和nginx-rtmp-module搭建流媒体服务器的正确姿势
  12. linux中的权限
  13. 创建一个QT for Android的传感器应用应用程序(摘自笔者2015年将出的《QT5权威指南》,本文为试读篇)
  14. 3星|《绩效使能:超越OKR》:较全较新资料汇编,华为实施经验少
  15. css高度自適應
  16. CSS预处理语言
  17. POJ - 1836 Alignment (动态规划)
  18. django 单元测试错误总结
  19. K8S 安装笔记
  20. hiho一下 第165周#1327 : 分隔相同字符

热门文章

  1. Xenu Link Sleuth 简单好用的链接测试工具 使用说明
  2. curl获取响应时间
  3. bootargs中ip段各项解释
  4. json的例子
  5. Theoretical &amp; Applied Mechanics Letters第2届编委会2015年度第1次全体编委会工作会议纪要(转自力学学会)
  6. git 常见报错
  7. How to Restart Qt Application
  8. 添加普通用户为sudo用户
  9. CodeForces 686A Free Ice Cream (水题模拟)
  10. m2e 插件