Silverlight 中使用不同面板进行布局的效果比较

      本文通过一个实例程序,比较Silverlight中应用面板控件Canvas,StackPanel,DockPanel,WrapPanel,Grid,VirtualizingStackPanel ,ViewBox来布局时,它们产生的效果异同。
一、不同面板的布局效果

二、源代码

 源代码下载

<UserControl xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"  xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"  x:Class="PanelLayout.MainPage"
    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"
    mc:Ignorable
="d"
    d:DesignHeight
="300" d:DesignWidth="800">

    
<Grid x:Name="LayoutRoot" Background="White" ShowGridLines="True">

        
<Grid.RowDefinitions>
            
<RowDefinition Height="50"/>
            
<RowDefinition Height="50*"/>
        
</Grid.RowDefinitions>
        
<Grid.ColumnDefinitions>
            
<ColumnDefinition Width="160*"/>
            
<ColumnDefinition Width="160*"/>
            
<ColumnDefinition Width="160*"/>
            
<ColumnDefinition Width="160*"/>
            
<ColumnDefinition Width="160*"/>
        
</Grid.ColumnDefinitions>
        
<sdk:Label Grid.Row="0" Grid.Column="0" HorizontalContentAlignment="Center" Content="Canvas"/>
        
<Canvas Grid.Row="1" Grid.Column="0">
            
<Button Background="Red">Left=0, Top=0</Button>
            
<Button Canvas.Left="18" Canvas.Top="18"
            Background
="Orange">Left=18, Top=18</Button>
        
</Canvas>
        
        
<sdk:Label Grid.Row="0" Grid.Column="1" HorizontalContentAlignment="Center" Content="StackPanel"/>
        
<StackPanel Grid.Row="1" Grid.Column="1" FlowDirection="LeftToRight" VerticalAlignment="Center">
            
<Button  Background="Red">1</Button>
            
<Button  Background="Orange">2</Button>
            
<Button  Background="Yellow">3</Button>
            
<Button  Background="Lime">4</Button>
            
<Button Background="Aqua">5</Button>
        
</StackPanel>

        
<sdk:Label Grid.Row="0" Grid.Column="2" HorizontalContentAlignment="Center" Content="DockPanel"/>
        
<toolkit:DockPanel  Grid.Row="1" Grid.Column="2"  VerticalAlignment="Center">
            
<Button  Background="Red">1</Button>
            
<Button  Background="Orange">2</Button>
            
<Button  Background="Yellow">3</Button>
            
<Button  Background="Lime">4</Button>
            
<Button Background="Aqua">5</Button>
        
</toolkit:DockPanel>



        
<sdk:Label Grid.Row="0" Grid.Column="3" HorizontalContentAlignment="Center" Content="WrapPanel"/>
        
<toolkit:WrapPanel Grid.Row="1" Grid.Column="3"  VerticalAlignment="Center">

            
<Button  Background="Red">1</Button>
            
<Button  Background="Orange">2</Button>
            
<Button  Background="Yellow">3</Button>
            
<Button  Background="Lime">4</Button>
            
<Button Background="Aqua">5</Button>
        
</toolkit:WrapPanel>

  
        
<sdk:Label Grid.Row="0" Grid.Column="4" HorizontalContentAlignment="Center" Content="Grid"/>
        
<Grid Grid.Row="1" Grid.Column="4">
            
<Grid.RowDefinitions>
                
<RowDefinition Height="20*"/>
                
<RowDefinition Height="20*"/>
                
<RowDefinition Height="20*"/>
                
<RowDefinition Height="20*"/>
            
</Grid.RowDefinitions>
            
<Grid.ColumnDefinitions>
                
<ColumnDefinition Width="20*"/>
                
<ColumnDefinition Width="20*"/>
                
<ColumnDefinition Width="20*"/>
                
<ColumnDefinition Width="20*"/>
                
<ColumnDefinition Width="20*"/>
            
</Grid.ColumnDefinitions>
        
            
<Button Grid.Row="1" Grid.Column="1" Grid.RowSpan="2" Grid.ColumnSpan="3" Background="Green"  BorderBrush="Red" BorderThickness="5" ></Button>
        
</Grid>

        
<sdk:GridSplitter Grid.Row="1" Grid.Column="0" Width="10" Background="Lime"/>
        
<sdk:GridSplitter Grid.Row="1" Grid.Column="1" Width="10" Background="Lime"/>
        
<sdk:GridSplitter Grid.Row="1" Grid.Column="2" Width="10" Background="Lime"/>
        
<sdk:GridSplitter Grid.Row="1" Grid.Column="3" Width="10" Background="Lime"/>
    
</Grid>
</UserControl>

三、通过分析它们的特点,得出它们适合应用的场合。

不同布局面板的特点:
1、Canvas
      Canvas 使您可以进行 (x,y) 定位,这与 GDI 和 GDI+ 目前提供的功能类似。您还可以使用附加的属性Left,Top来控制

项的位置。
2、DockPanel
      DockPanel使您在停靠项时无需担心它们的确切 (x,y) 位置。
3、StackPanel 提供一个从左至右(水平)或从上至下(垂直)放置内容的堆栈模型。
      StackPanel的默认排列方式为Vertical(垂直),但是如果你想指定为Horizontal(水平),
      那么你可以使用属性Orientation="Horizontal"。

 如: <StackPanel Grid.Row="1" Grid.Column="1" FlowDirection="LeftToRight" VerticalAlignment="Center" Orientation="Horizontal"/>

 4、WrapPanel
WrapPanel用于在水平方向或垂直方向顺序显示子元素,当到达边缘时,则本行不足以显示的子元素对象自动换到下一行顺序显示。

5、Grid
     Grid 提供一个允许进行行/网格定位的模型:
     可用 SharedSizeGroup 属性为多个对象指定共享的大小。
     例如,可使用该属性来指定两个按钮具有相同的宽度(即使它们通常具有不同的大小范围)。

<Border xmlns="http://schemas.microsoft.com/winfx/avalon/2005">
<Grid LayoutTransform="scale 2" ShowGridLines="true" IsSharedSizeScope="true" Height="80">
<ColumnDefinition Width="30" />
<ColumnDefinition Width="Auto" SharedSizeGroup="Buttons" />
<ColumnDefinition Width="Auto" SharedSizeGroup="Buttons" />
<RowDefinition />
<Button Grid.Column="1" Margin="10">OK</Button>
<Button Grid.Column="2" Margin="10">A very long cancel button</Button>
</Grid>

   可以指定元素使用Grid 的RowSpan,ColumnSpan来设置元素占用Grid的表格数量。效果如上图右边效果显示。

        <Grid Grid.Row="1" Grid.Column="4">
            
<Grid.RowDefinitions>
                
<RowDefinition Height="20*"/>
                
<RowDefinition Height="20*"/>
                
<RowDefinition Height="20*"/>
                
<RowDefinition Height="20*"/>
            
</Grid.RowDefinitions>
            
<Grid.ColumnDefinitions>
                
<ColumnDefinition Width="20*"/>
                
<ColumnDefinition Width="20*"/>
                
<ColumnDefinition Width="20*"/>
                
<ColumnDefinition Width="20*"/>
                
<ColumnDefinition Width="20*"/>
            
</Grid.ColumnDefinitions>
 
<Button Grid.Row="1" Grid.Column="1" Grid.RowSpan="2" Grid.ColumnSpan="3" Background="Green"  BorderBrush="Red" BorderThickness="5" >
                
<Button.Content>
                    
<Grid>
                        
<Grid.RowDefinitions>
                            
<RowDefinition></RowDefinition>
                            
<RowDefinition ></RowDefinition>
                        
</Grid.RowDefinitions>
                        
<Image Source="Images/note.png"  Grid.Row="0">
                        
</Image>
                        
<TextBlock Text="FRJ提醒" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center">
                        
</TextBlock>
                    
</Grid>
                
</Button.Content>
            
</Button>

6、ViewBox

ViewBox 具有约束内容的大小以适应父面板的相反效果。这就提供了一种自动缩放效果。

以下示例中的文字,将根据窗口的大小,自动变大与缩小。

    <Grid x:Name="LayoutRoot" Background="White">
        <Border>
            <Viewbox>
                <TextBlock FontFamily="Global User Interface"> 人之初,性本善,性相近,习相远。苟不教,性乃迁,教之道,贵以专。</TextBlock>
            </Viewbox>
        </Border>     

    </Grid>

7、VirtualizingStackPanel
         将内容排列和虚拟化在一行上,方向为水平或垂直。      
         VirtualizingStackPanel在普通StackPanel的基础上,提供了”虚拟化”的功能。那什么是”虚拟化”呢?先来看一个场景,如果你有一堆基于项的数据,并且你只需要让其中一部分显示在界面上,但是如果你针对里面所有的数据创建界面元素,并显示你需要的元素,那么这将是及其耗时的。”虚拟化”就是用于解决这个问题,它可以只创建你需要显示的数据的界面元素。即 “虚拟化”是指一种技术,通过该技术,可根据屏幕上所显示的项来从大量数据项中生成user interface (UI) 元素的子集。
         VirtualizingStackPanel中的项只有在数据绑定的状态下,才提供”虚拟化”,否则和普通的StackPanel没有区别。
        即仅当 StackPanel 中包含的项控件创建自己的项容器时,才会在该面板中发生虚拟化。 可以使用数据绑定来确保发生这一过程。 如果创建项容器并将其添加到项控件中,则与 StackPanel 相比,VirtualizingStackPanel 不能提供任何性能优势。
        应用示例:
        http://msdn.microsoft.com/zh-cn/library/system.windows.controls.virtualizingstackpanel.aspx
        下面的示例演示如何使用Extensible Application Markup Language (XAML) 绑定到 XML 数据源,并虚拟化 ListBox 元素中显示的项。 注意:IsVirtualizing 附加属性显式设置为 true。

 <Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml" 
      WindowTitle
="VirtualizingStackPanel Sample" 
      Height
="150"
      VerticalAlignment
="Top">
    
<Page.Resources>
        
<XmlDataProvider x:Key="Leagues" Source="Leagues.xml" XPath="Leagues/League"/>

    
<DataTemplate x:Key="NameDataStyle">
      
<TextBlock Text="{Binding XPath=@name}" FontFamily="Arial" FontSize="12" Foreground="Black"/>
    
</DataTemplate>

    
</Page.Resources>
  
<Border HorizontalAlignment="Left" 
          VerticalAlignment
="Top" 
          BorderBrush
="Black" 
          BorderThickness
="2">
       
<ScrollViewer>
      
<StackPanel DataContext="{Binding Source={StaticResource Leagues}}">
          
<TextBlock Text="{Binding XPath=@name}" FontFamily="Arial" FontSize="18" Foreground="Black"/>
              
<ListBox VirtualizingStackPanel.IsVirtualizing="True" 
                       ItemsSource
="{Binding XPath=Team}" 
                       ItemTemplate
="{DynamicResource NameDataStyle}"/>      
      
</StackPanel>
      
</ScrollViewer>
  
</Border>    
</Page>

下面的示例创建一个 ListBox,并将 VirtualizingStackPanel.VirtualizationMode 附加属性设置为 Recycling。

<StackPanel>

  
<StackPanel.Resources>
    
<src:LotsOfItems x:Key="data"/>
  
</StackPanel.Resources>

  
<ListBox Height="150" ItemsSource="{StaticResource data}" 
             VirtualizingStackPanel.VirtualizationMode
="Recycling" />

</StackPanel>

下面的示例演示上例中所使用的数据。

public class LotsOfItems : ObservableCollection<String>
{
    
public LotsOfItems()
    {
        
for (int i = 0; i < 1000++i)
        {
            Add(
"item " + i.ToString());
        }
    }
}

     布局是任何用户界面子系统的基础服务之一,它涉及如何确定元素在窗口中的位置。设计 Windows Presentation Foundation 布局系统的目的是为灵活的可扩展模型提供支持,该模型针对内容进行优化,并且能够正确地处理数据、样式和控件。
     传统的应用程序平台(如 Win32)几乎没有布局的概念:控件放置在画布上的 (x,y) 坐标系中,并且开发人员需要手动提供对确定任何元素的原点和尺寸的支持(考虑窗口大小调整和显示器 DPI 设置)。另一方面,Windows Presentation Foundation 提供多种适合于内容并且在窗口内管理控件和项目位置的布局实现。
在 Windows Presentation Foundation 中,几乎可以使用任何元素作为其他元素的宿主。例如,Button 可按如下方式包含图像:

<Button Grid.Row="1" Grid.Column="1" Grid.RowSpan="2" Grid.ColumnSpan="3" Background="Green"    BorderBrush="Red" BorderThickness="5" >
                
<Button.Content>
                    
<Grid>
                        
<Grid.RowDefinitions>
                            
<RowDefinition></RowDefinition>
                            
<RowDefinition ></RowDefinition>
                        
</Grid.RowDefinitions>
                        
<Image Source="Images/note.png"  Grid.Row="0">
                        
</Image>
                        
<TextBlock Text="FRJ提醒" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center">
                        
</TextBlock>
                    
</Grid>
                
</Button.Content>
            
</Button>


      面板负责其子元素的布局。它们定义内容的大小和形状、对齐方式和边距。面板的子元素可以是诸如 TextBox 或 Button 这样的元素,也可以是另一个面板。
例如,DockPanel 可以包含 StackPanel 项调整大小以适应它们所包含的内容 — 这是一个重要的概念,因为它确保了应用程序的本地化不需要重新校准应用程序布局(因为不同语言的同一句子 — 例如“Auf Wiedersehen”与“Goodbye”— 具有不同的文本长度)。可用 HorizontalAlignment/VerticalAlignment 属性应用对齐方式,并且使用 Margin 属性指定边距。ScrollViewer 提供子元素内容的滚动视图;如果内容溢出可用的空间,则会显示一个滚动条并允许用户在内容区域周围移动。
例如:

<Border >

<ScrollViewer>     

<TextBlock FontSize="20" TextWrapping="Wrap" FontFamily="Global User Interface">

      人之初,性本善,性相近,习相远。苟不教,性乃迁,教之道,贵以专。

  昔孟母,择邻处,子不学,断机杼。窦燕山,有义方,教五子,名俱扬。

  养不教,父之过,教不严,师之惰。子不学,非所宜,幼不学,老何为?

  玉不琢,不成器,人不学,不知义。为人子,方少时,亲师友,习礼仪。

  香九龄,能温席,孝于亲,所当执。融四岁,能让梨,悌于长,宜先知。       

</TextBlock>  

</ScrollViewer>

</Border>

      布局协议是一个递归过程,它是某种形式的协商,目的是确保所有元素都基于其请求获得“公平”数量的空间。首先,将发生一个测量过程,其中,父元素询问子元素希望自己多大,而子元素用 DesiredSize 进行响应。然后,将发生排列过程,其中,父元素以 ActualSize 属性的形式告诉子元素它将有多大。在进行计算时,特殊值 Double.PositiveInfinity 意味着“适合于内容”。可通过重写面板的 MeasureOverride 和 ArrangeOverride 元素来处理这一问题。


         

原文地址:https://www.cnblogs.com/furenjun/p/2036896.html