本系列对实际项目中的XAML布局场景进行总结,给出了较优化的自适应布局解决方案,希望对大家有所帮助。

下面继续介绍局部布局设计模式。

5. 工具箱模式

绘图,三维模型操作等需要工具的情况,可以使用带分类的工具箱来放置工具,以达到较好的效果。实现工具箱效果的方法是使用ItemsControl的分组功能,并修改样式和布局。

首先,在最外层放置一个横向滚动条为Auto的ScrollViewer。里面放一个ItemsControl,修改布局为UniformGrid,分两行。ItemTemplate为Button,设置合适的背景色和固定长度宽度(和字体字号相关),并设置左和上的Margin。Button的Content为TextBlock,设置文字折行和截断,并设置横向和纵向对齐方式为居中。TextBlock可设置合适的ToolTip,可使用转换器控制只在文字多的时候显示。

然后,修改ItemTemplate的GroupStyle,GroupStyle的Panel为横向的StackPanel,ContainerStyle的Template放置一个横向的StackPanel,分别放一个Rectangle做为分割竖线和一个Grid放置真正的内容。Rectangle使用转换器控制在第一个位置时不显示。Grid分为两行,第0行为Auto,第1行为*,第0行为一个放在Border里的TextBlock,设置Margin和居中对齐。第1行是ItemsPresenter,设置Margin的右和下,以和前面呼应。

最后,绑定到合适的数据源,数据源为CollectionViewSource,其Source属性为一个数据集合,数据包含ClassName和Name属性,ClassName是分类名称,Name是条目名称。在CollectionViewSource的GroupDescriptions属性中加入名为ClassName的PropertyGroupDescription。在XAML中设置合适的数据绑定即可。

<Window x:Class="BlendDemo.DP5"
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"
xmlns:local="clr-namespace:BlendDemo"
mc:Ignorable="d"
Title="工具箱模式" Height="400" Width="500">
<Window.Resources>
<local:SeparatorVisibilityConverter x:Key="SeparatorVisibilityConverter"/>
<local:LengthVisibilityConverter x:Key="LengthVisibilityConverter"/>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Background="LightCyan">
<TextBlock Margin="5" Text="此处为标题" TextTrimming="WordEllipsis"/>
</Border>
<Grid Grid.Row="1" Background="AliceBlue"/>
<Grid Grid.Row="2">
<ScrollViewer HorizontalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="2"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Background="AliceBlue" Width="70" MaxHeight="40" Margin="5,5,0,0">
<TextBlock Text="{Binding Name}" TextWrapping="Wrap" TextTrimming="WordEllipsis" HorizontalAlignment="Center" VerticalAlignment="Center"
ToolTipService.Placement="Bottom" ToolTipService.InitialShowDelay="0" ToolTipService.BetweenShowDelay="0">
<TextBlock.ToolTip>
<ToolTip Content="{Binding Name}" Visibility="{Binding Path=Name, Converter={StaticResource LengthVisibilityConverter}, ConverterParameter=10}"/>
</TextBlock.ToolTip>
</TextBlock>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.GroupStyle>
<GroupStyle>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</GroupStyle.Panel>
<GroupStyle.ContainerStyle>
<Style TargetType="GroupItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<StackPanel Orientation="Horizontal">
<Rectangle Fill="#9ca1ae" Width="2" Visibility="{Binding Path=Name, Converter={StaticResource SeparatorVisibilityConverter}}"/>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Background="#e6e9f2">
<TextBlock Text="{Binding Name}" Margin="5" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ItemsPresenter Grid.Row="1" Margin="0,0,5,5"/>
</Grid>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ItemsControl.GroupStyle>
</ItemsControl>
</ScrollViewer>
</Grid>
</Grid>
</Window>
    public class SeparatorVisibilityConverter : IValueConverter
{
public IList Data { get; set; } public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (Data == null || Data.Count == 0)
{
return Visibility.Collapsed;
}
dynamic item = Data[0];
return ((string)value) == item.ClassName ? Visibility.Collapsed : Visibility.Visible;
} public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
} public class LengthVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
{
return Visibility.Collapsed;
}
return ((string)value).Length < int.Parse((string)parameter) ? Visibility.Collapsed : Visibility.Visible;
} public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
} public class DataItem
{
public string ClassName { get; set; }
public string Name { get; set; }
} public partial class DP5 : Window
{
public DP5()
{
InitializeComponent();
var cvs = new CollectionViewSource();
cvs.Source = new List<DataItem>
{
new DataItem { ClassName="分类1",Name="条目1.1"},
new DataItem { ClassName="分类1",Name="条目1.2"},
new DataItem { ClassName="分类1",Name="条目1.3为长条目"},
new DataItem { ClassName="分类1",Name="条目1.4"},
new DataItem { ClassName="分类1",Name="条目1.5"},
new DataItem { ClassName="分类2",Name="条目2.1"},
new DataItem { ClassName="分类2",Name="条目2.2"},
new DataItem { ClassName="分类2",Name="条目2.3"},
new DataItem { ClassName="分类2",Name="条目2.4"},
new DataItem { ClassName="分类2",Name="条目2.5"},
new DataItem { ClassName="分类2",Name="条目2.6为长条目长条目长条目长条目"},
new DataItem { ClassName="分类3",Name="条目3.1"},
new DataItem { ClassName="分类3",Name="条目3.2"},
new DataItem { ClassName="分类3",Name="条目3.3"},
new DataItem { ClassName="分类3",Name="条目3.4"},
};
cvs.GroupDescriptions.Add(new PropertyGroupDescription("ClassName"));
DataContext = cvs;
((SeparatorVisibilityConverter)FindResource("SeparatorVisibilityConverter")).Data = (IList)cvs.Source;
}
}

6. 选择题模式

制作选择题考试界面时,需要达到纸质选择题考试的效果。选项的排列方式分几种情况,选项文字少的时候排在一行上,文字不太多的时候分两列排,文字较多的时候按一列排。

首先,构造合适的数据结构,并加入一些示例数据。编写一个模板选择器,用于根据选项的数据情况选择合适的显示模板。全部选项的文字都小于4个字时,使用折行选项模板。全部选项的文字都小于10个字时,使用两列选项模板。其他情况使用一列选项模板。

然后,分别编写模板。折行选项模板使用ItemsControl,布局改为WrapPanel,数据模板使用StackPanel,其中放置序号,点和内容。两列选项模板使用ItemsControl,布局改为UniformGrid,列数为2,数据模板使用Grid,分为3列,前2列为Auto,放置序号和点,最后1列为*,放置显示Content的TextBlock,并设置折行。一列选项模板使用ItemsControl,不修改布局,数据模板和两列的情况相同。

最后,选择题的整体显示使用放置在ScrollViewer中的ItemsControl,不修改布局。数据模板使用StackPanel,首先放置一个Grid,分为3列,前2列为Auto,放置序号和点,最后1列为*,放置显示问题的TextBlock,并设置折行。下面放一个ContentControl,Content绑定到合适的数据,并设置ContentTemplateSelector为前文所述的模板选择器。

<Window x:Class="BlendDemo.DP6"
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"
xmlns:local="clr-namespace:BlendDemo"
mc:Ignorable="d"
Title="选择题模式" Height="400" Width="650">
<Window.Resources>
<DataTemplate x:Key="WrapOptionTemplate">
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,4,70,4">
<TextBlock Text="{Binding Index}"/>
<TextBlock Text="." Margin="3,0,3,0"/>
<TextBlock Text="{Binding Content}" TextWrapping="Wrap"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
<DataTemplate x:Key="TwoColumnOptionTemplate">
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="0,4,0,4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Index}"/>
<TextBlock Grid.Column="1" Text="." Margin="3,0,3,0"/>
<TextBlock Grid.Column="2" Text="{Binding Content}" TextWrapping="Wrap"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="2"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
<DataTemplate x:Key="OneColumnOptionTemplate">
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="0,4,0,4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Index}"/>
<TextBlock Grid.Column="1" Text="." Margin="3,0,3,0"/>
<TextBlock Grid.Column="2" Text="{Binding Content}" TextWrapping="Wrap"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</Window.Resources>
<Grid>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding}" Margin="20,20,20,3">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,7">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Index}" TextWrapping="Wrap"/>
<TextBlock Grid.Column="1" Text="." TextWrapping="Wrap" Margin="0,0,5,0"/>
<TextBlock Grid.Column="2" TextWrapping="Wrap" Text="{Binding Question}"/>
</Grid>
<ContentControl Content="{Binding OptionList}" Margin="33,10,33,10">
<ContentControl.ContentTemplateSelector>
<local:OptionTemplateSelector/>
</ContentControl.ContentTemplateSelector>
</ContentControl>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</Window>
    public class OptionItem
{
public string Index { get; set; } public string Content { get; set; } } public class ObjectiveTestItem
{
public int Index { get; set; } public string Question { get; set; } public List<OptionItem> OptionList { get; set; } } public class OptionTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var element = container as FrameworkElement;
if (element == null) return null;
var optionAnswerItems = item as List<OptionItem>;
if (optionAnswerItems == null) return null;
if (optionAnswerItems.All(i => i.Content.Length <= 4))
{
return element.FindResource("WrapOptionTemplate") as DataTemplate;
}
if (optionAnswerItems.All(i => i.Content.Length <= 10))
{
return element.FindResource("TwoColumnOptionTemplate") as DataTemplate;
}
return element.FindResource("OneColumnOptionTemplate") as DataTemplate;
} } public partial class DP6 : Window
{
public DP6()
{
InitializeComponent();
var data = new List<ObjectiveTestItem>();
var item1 = new ObjectiveTestItem
{
Index = 1,
Question = "短的选项",
OptionList = new List<OptionItem>
{
new OptionItem { Index="A",Content="选项1" },
new OptionItem { Index="B",Content="选项2" },
new OptionItem { Index="C",Content="选项2" },
new OptionItem { Index="D",Content="选项2" }
}
};
data.Add(item1);
var item2 = new ObjectiveTestItem
{
Index = 1,
Question = "中等长度的选项",
OptionList = new List<OptionItem>
{
new OptionItem { Index="A",Content="中等长度的选项1" },
new OptionItem { Index="B",Content="选项2" },
new OptionItem { Index="C",Content="选项2" },
new OptionItem { Index="D",Content="选项2" }
}
};
data.Add(item2);
var item3 = new ObjectiveTestItem
{
Index = 1,
Question = "长的选项长的选项长的选项长的选项长的选项长的选项长的选项长的选项长的选项长的选项长的选项长的选项长的选项",
OptionList = new List<OptionItem>
{
new OptionItem { Index="A",Content="长的选项长的选项长的选项长的选项长的选项长的选项长的选项1" },
new OptionItem { Index="B",Content="选项2" },
new OptionItem { Index="C",Content="选项2" },
new OptionItem { Index="D",Content="选项2" }
}
};
data.Add(item3);
DataContext = data;
}
}

自适应XAML布局经验总结 (三) 局部布局设计模式2的更多相关文章

  1. DIV+CSS 网页布局之:三列布局

    1.宽度自适应三列布局 三列布局的原理和两列布局的原理是一样的,只不过多了一列,只需给宽度自适应两列布局中间再加一列,然后重新计算三列的宽度,就实现了宽度自适应的三列布局. 同样的道理,更多列的布局, ...

  2. 如何用CSS实现中间自适应,两边定宽三栏布局

    1.前言 用css实现“两边定宽,中间自适应的三栏布局”这个问题应该是在前端面试中被面试官提问到的高频问题了,一般当面试者写出一种实现方法之后,面试官还会问你还有没有别的方法,尽量多的写出几种实现方法 ...

  3. Android 布局详解 -三表格布局(TableLayout)以及重要属性

              TableLayout跟TableRow 是一组搭配应用的布局,TableLayout置底,TableRow在TableLayout的上方,而Button.TextView等控件就 ...

  4. 如何用CSS实现左侧宽度固定,右侧自适应(两栏布局)?左右固定中间自适应(三栏布局)呢?

    在前端日常布局中,会经常遇到左侧宽度固定,右侧自适应或者左右两边固定,中间部分自适应的实用场景.本文例子中将列举出两种常用的两栏布局,左侧固定右侧自适应的常用方法以及代码和五种左右固定中间自适应的常用 ...

  5. 简单的CSS网页布局--三列布局

    三列布局其实不难,不过要用到position:absolute这个属性,因为这个属性是基于浏览器而言,左右部分各放在左右侧,空出中间一列来实现三列布局. (一)三列布局自适应 <!DOCTYPE ...

  6. css布局笔记(三)圣杯布局,双飞翼布局

    圣杯布局和双飞翼布局都是三列布局,两边定宽,中间自适应布局,中间栏要在放在文档流前面以优先渲染. 圣杯布局如下 <!-- 圣杯布局 --> <!DOCTYPE html> &l ...

  7. CSS布局——三栏布局

    说到三栏布局,很多都会提到圣杯布局和双飞翼布局这两个经典的三栏布局方式.于是,我在网上搜了一些相关资料,阅读并跟着代码敲了一遍,发现在处理三栏布局上,他们采用的都是两边栏固定,中间栏自适应的策略.在处 ...

  8. ccs之经典布局(二)(两栏,三栏布局)

    接上篇ccs之经典布局(一)(水平垂直居中) 四.两列布局 单列宽度固定,另一列宽度是自适应. 1.float+overflow:auto; 固定端用float进行浮动,自适应的用overflow:a ...

  9. CSS三种布局模型是什么?

    在网页中,元素有三种布局模型:流动模型(Flow) 默认的.浮动模型 (Float).层模型(Layer).下面我们来看一下这三种布局模型. 三种布局模型介绍: 1.流动模型(Flow) 流动(Flo ...

随机推荐

  1. 获取RequestMapping注解中的属性

    参考:https://www.cnblogs.com/2013jiutian/p/7294053.html @RequestMapping("/value1") @Controll ...

  2. zoj1649-Rescue (迷宫最短路径)【bfs 优先队列】

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=649 Rescue Time Limit: 2 Seconds      Mem ...

  3. mysql数据库的最基本的命令

    #查看mysql有哪些数据库:show databases; 创建一个数据库名称为DataBaseName,字符编码为utf8支持中文create database DataBaseName char ...

  4. python单线程下实现多个socket并发

    先看服务端的代码 import sys # import socket import time import gevent from gevent import socket from gevent ...

  5. jquery正则表达式验证:验证身份证号码

    需求说明: 前端页面使用正则表达式验证文本输入框输入的身份证号码是否符合规则. 代码说明: 这里只介绍正则表达式部分,其他部分的代码不做介绍.如有其它需求请自行修改即可. 步骤一:建立一个页面可以是h ...

  6. PHP+Gtk实例(求24点)

    作者: Laruence(   ) 本文地址: http://www.laruence.com/2009/05/26/871.html 转载请注明出处 最近要安排我为BIT提供的<PHP高级应用 ...

  7. PAT 1083 是否存在相等的差(20)(代码+思路)

    1083 是否存在相等的差(20 分) 给定 N 张卡片,正面分别写上 1.2.--.N,然后全部翻面,洗牌,在背面分别写上 1.2.--.N.将每张牌的正反两面数字相减(大减小),得到 N 个非负差 ...

  8. jquery节点获取

    jQuery.parent(expr)  找父亲节点,可以传入expr进行过滤,比如$("span").parent()或者$("span").parent(& ...

  9. Java数据结构和算法(一)概念

    Java数据结构和算法(一)概念 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 一.逻辑结构 数据之间的相互关系称为逻辑结构 ...

  10. bat批量重命名文件

    @echo off setlocal enabledelayedexpansion set prefix="mai" set /a num=000 rem 排序/o:? -代表逆序 ...