自适应XAML布局经验总结 (三) 局部布局设计模式2
本系列对实际项目中的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的更多相关文章
- DIV+CSS 网页布局之:三列布局
1.宽度自适应三列布局 三列布局的原理和两列布局的原理是一样的,只不过多了一列,只需给宽度自适应两列布局中间再加一列,然后重新计算三列的宽度,就实现了宽度自适应的三列布局. 同样的道理,更多列的布局, ...
- 如何用CSS实现中间自适应,两边定宽三栏布局
1.前言 用css实现“两边定宽,中间自适应的三栏布局”这个问题应该是在前端面试中被面试官提问到的高频问题了,一般当面试者写出一种实现方法之后,面试官还会问你还有没有别的方法,尽量多的写出几种实现方法 ...
- Android 布局详解 -三表格布局(TableLayout)以及重要属性
TableLayout跟TableRow 是一组搭配应用的布局,TableLayout置底,TableRow在TableLayout的上方,而Button.TextView等控件就 ...
- 如何用CSS实现左侧宽度固定,右侧自适应(两栏布局)?左右固定中间自适应(三栏布局)呢?
在前端日常布局中,会经常遇到左侧宽度固定,右侧自适应或者左右两边固定,中间部分自适应的实用场景.本文例子中将列举出两种常用的两栏布局,左侧固定右侧自适应的常用方法以及代码和五种左右固定中间自适应的常用 ...
- 简单的CSS网页布局--三列布局
三列布局其实不难,不过要用到position:absolute这个属性,因为这个属性是基于浏览器而言,左右部分各放在左右侧,空出中间一列来实现三列布局. (一)三列布局自适应 <!DOCTYPE ...
- css布局笔记(三)圣杯布局,双飞翼布局
圣杯布局和双飞翼布局都是三列布局,两边定宽,中间自适应布局,中间栏要在放在文档流前面以优先渲染. 圣杯布局如下 <!-- 圣杯布局 --> <!DOCTYPE html> &l ...
- CSS布局——三栏布局
说到三栏布局,很多都会提到圣杯布局和双飞翼布局这两个经典的三栏布局方式.于是,我在网上搜了一些相关资料,阅读并跟着代码敲了一遍,发现在处理三栏布局上,他们采用的都是两边栏固定,中间栏自适应的策略.在处 ...
- ccs之经典布局(二)(两栏,三栏布局)
接上篇ccs之经典布局(一)(水平垂直居中) 四.两列布局 单列宽度固定,另一列宽度是自适应. 1.float+overflow:auto; 固定端用float进行浮动,自适应的用overflow:a ...
- CSS三种布局模型是什么?
在网页中,元素有三种布局模型:流动模型(Flow) 默认的.浮动模型 (Float).层模型(Layer).下面我们来看一下这三种布局模型. 三种布局模型介绍: 1.流动模型(Flow) 流动(Flo ...
随机推荐
- 日志记录发布网站之后不成功,对路径“C:\Inetpub\wwwroot\***\***.xls”的访问被拒绝。
主要是web程序的根目录文件夹路径访问权限不够,新增加一个everyone的完全控制读写的权限即可!---------折磨了两天,才发现使劲使错了地方. 另外: 一定谨记!!!!! 所写的路径如果不存 ...
- 《Visual Basic开发实战1200例》包括第I卷、第II卷共计1200个例子,本书是第I卷,共计600个例子。
本书以开发人员在项目开发中经常遇到的问题和必须掌握的技术为中心,介绍了应用Visual Basic进行程序开发各个方面的知识和技巧.主要包括基础知识.窗体界面设计.控件应用等.全书分6篇20章,共计6 ...
- subprocess 粘包问题
1.执行命令: 在py代码中去如何调用操作系统的命令 新模块:subprocess r = subprocess.Popen('ls',shell=True,stdout=subprocess.PIP ...
- 115. Distinct Subsequences (String; DP)
Given a string S and a string T, count the number of distinct subsequences of T in S. A subsequence ...
- SVN客户端的安装和使用
----------------------siwuxie095 SVN 客户端的安装 1.SVN 客户端,选择 TortoiseSVN,下载链接: https://tortoisesvn.net/d ...
- PostgreSQL+pgpool-II复制方案
目录 PostgreSQL+pgpool-II复制方案 1. Pgpool-II介绍 2. pgpool-II安装 2.1 安装pgpool-II yum源,并安装pgpool-II 2.2 添加Pg ...
- 【转】从源码浅析MVC的MvcRouteHandler、MvcHandler和MvcHttpHandler
原文:http://www.cnblogs.com/jeffwongishandsome/archive/2012/01/08/2316521.html 熟悉WebForm开发的朋友一定都知道,Pag ...
- Web前端工程师常去的15个技术网站
1.CSDN 网址:https://www.csdn.net/ 简介: CSDN (Chinese Software Developer Network) 创立于1999年,是中国最大的IT社区和服务 ...
- laravel中的old()函数
1.控制器 2.模板
- [SoapUI] 比较JSON Response
比较两个JSON, ID是数字时,处理成统一的格式:只保留小数点后5位 package direct; import org.json.JSONArray; import org.json.JSONE ...